include/elf/
[deliverable/binutils-gdb.git] / gas / config / tc-alpha.c
index b249ff04a9532e3817365ae7978c211e34534000..1ba7aca6b04ed3530525944d050c0911b89cee8c 100644 (file)
@@ -1,5 +1,6 @@
 /* tc-alpha.c - Processor-specific code for the DEC Alpha AXP CPU.
-   Copyright (C) 1989, 93-98, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002 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.
@@ -61,8 +62,7 @@
 #include "dwarf2dbg.h"
 #endif
 
-#include <ctype.h>
-
+#include "safe-ctype.h"
 \f
 /* Local types */
 
 #define MAX_INSN_FIXUPS 2
 #define MAX_INSN_ARGS 5
 
-struct alpha_fixup
-{
+struct alpha_fixup {
   expressionS exp;
   bfd_reloc_code_real_type reloc;
 };
 
-struct alpha_insn
-{
+struct alpha_insn {
   unsigned insn;
   int nfixups;
   struct alpha_fixup fixups[MAX_INSN_FIXUPS];
-  unsigned sequence[MAX_INSN_FIXUPS];
+  long sequence;
 };
 
-enum alpha_macro_arg
-{
+enum alpha_macro_arg {
   MACRO_EOA = 1,
   MACRO_IR,
   MACRO_PIR,
@@ -95,14 +92,9 @@ enum alpha_macro_arg
   MACRO_CPIR,
   MACRO_FPR,
   MACRO_EXP,
-  MACRO_LITERAL,
-  MACRO_BASE,
-  MACRO_BYTOFF,
-  MACRO_JSR
 };
 
-struct alpha_macro
-{
+struct alpha_macro {
   const char *name;
   void (*emit) PARAMS ((const expressionS *, int, const PTR));
   const PTR arg;
@@ -114,19 +106,45 @@ struct alpha_macro
 #define O_pregister    O_md1   /* O_register, in parentheses */
 #define O_cpregister   O_md2   /* + a leading comma */
 
-#ifdef RELOC_OP_P
-/* Note, the alpha_reloc_op table below depends on the ordering
-   of O_literal .. O_gprelow.  */
+/* The alpha_reloc_op table below depends on the ordering of these.  */
 #define O_literal      O_md3   /* !literal relocation */
-#define O_lituse_base  O_md4   /* !lituse_base relocation */
-#define O_lituse_bytoff        O_md5   /* !lituse_bytoff relocation */
-#define O_lituse_jsr   O_md6   /* !lituse_jsr relocation */
-#define O_gpdisp       O_md7   /* !gpdisp relocation */
-#define O_gprelhigh    O_md8   /* !gprelhigh relocation */
-#define O_gprellow     O_md9   /* !gprellow relocation */
-
-#define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_gprellow)
-#endif
+#define O_lituse_addr  O_md4   /* !lituse_addr relocation */
+#define O_lituse_base  O_md5   /* !lituse_base relocation */
+#define O_lituse_bytoff        O_md6   /* !lituse_bytoff relocation */
+#define O_lituse_jsr   O_md7   /* !lituse_jsr relocation */
+#define O_lituse_tlsgd O_md8   /* !lituse_tlsgd relocation */
+#define O_lituse_tlsldm        O_md9   /* !lituse_tlsldm relocation */
+#define O_gpdisp       O_md10  /* !gpdisp relocation */
+#define O_gprelhigh    O_md11  /* !gprelhigh relocation */
+#define O_gprellow     O_md12  /* !gprellow relocation */
+#define O_gprel                O_md13  /* !gprel relocation */
+#define O_samegp       O_md14  /* !samegp relocation */
+#define O_tlsgd                O_md15  /* !tlsgd relocation */
+#define O_tlsldm       O_md16  /* !tlsldm relocation */
+#define O_gotdtprel    O_md17  /* !gotdtprel relocation */
+#define O_dtprelhi     O_md18  /* !dtprelhi relocation */
+#define O_dtprello     O_md19  /* !dtprello relocation */
+#define O_dtprel       O_md20  /* !dtprel relocation */
+#define O_gottprel     O_md21  /* !gottprel relocation */
+#define O_tprelhi      O_md22  /* !tprelhi relocation */
+#define O_tprello      O_md23  /* !tprello relocation */
+#define O_tprel                O_md24  /* !tprel relocation */
+
+#define DUMMY_RELOC_LITUSE_ADDR                (BFD_RELOC_UNUSED + 1)
+#define DUMMY_RELOC_LITUSE_BASE                (BFD_RELOC_UNUSED + 2)
+#define DUMMY_RELOC_LITUSE_BYTOFF      (BFD_RELOC_UNUSED + 3)
+#define DUMMY_RELOC_LITUSE_JSR         (BFD_RELOC_UNUSED + 4)
+#define DUMMY_RELOC_LITUSE_TLSGD       (BFD_RELOC_UNUSED + 5)
+#define DUMMY_RELOC_LITUSE_TLSLDM      (BFD_RELOC_UNUSED + 6)
+
+#define LITUSE_ADDR    0
+#define LITUSE_BASE    1
+#define LITUSE_BYTOFF  2
+#define LITUSE_JSR     3
+#define LITUSE_TLSGD   4
+#define LITUSE_TLSLDM  5
+
+#define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_tprel)
 
 /* Macros for extracting the type and number of encoded register tokens */
 
@@ -181,7 +199,7 @@ struct alpha_macro
                                 (t).X_add_number = (r))
 #define set_tok_freg(t, r)     (memset (&(t), 0, sizeof (t)),          \
                                 (t).X_op = O_register,                 \
-                                (t).X_add_number = (r)+32)
+                                (t).X_add_number = (r) + 32)
 #define set_tok_sym(t, s, a)   (memset (&(t), 0, sizeof (t)),          \
                                 (t).X_op = O_symbol,                   \
                                 (t).X_add_symbol = (s),                \
@@ -189,10 +207,12 @@ struct alpha_macro
 #define set_tok_const(t, n)    (memset (&(t), 0, sizeof (t)),          \
                                 (t).X_op = O_constant,                 \
                                 (t).X_add_number = (n))
-
 \f
 /* Prototypes for all local functions */
 
+static struct alpha_reloc_tag *get_alpha_reloc_tag PARAMS ((long));
+static void alpha_adjust_symtab_relocs PARAMS ((bfd *, asection *, PTR));
+
 static int tokenize_arguments PARAMS ((char *, expressionS *, int));
 static const struct alpha_opcode *find_opcode_match
   PARAMS ((const struct alpha_opcode *, const expressionS *, int *, int *));
@@ -202,16 +222,15 @@ static unsigned insert_operand
   PARAMS ((unsigned, const struct alpha_operand *, offsetT, char *, unsigned));
 static void assemble_insn
   PARAMS ((const struct alpha_opcode *, const expressionS *, int,
-          struct alpha_insn *));
+          struct alpha_insn *, bfd_reloc_code_real_type));
 static void emit_insn PARAMS ((struct alpha_insn *));
 static void assemble_tokens_to_insn
   PARAMS ((const char *, const expressionS *, int, struct alpha_insn *));
 static void assemble_tokens
   PARAMS ((const char *, const expressionS *, int, int));
 
-static int load_expression
-  PARAMS ((int, const expressionS *, int *, expressionS *,
-          const expressionS *));
+static long load_expression
+  PARAMS ((int, const expressionS *, int *, expressionS *));
 
 static void emit_ldgp PARAMS ((const expressionS *, int, const PTR));
 static void emit_division PARAMS ((const expressionS *, int, const PTR));
@@ -262,17 +281,14 @@ static void s_alpha_base PARAMS ((int));
 static void s_alpha_align PARAMS ((int));
 static void s_alpha_stringer PARAMS ((int));
 static void s_alpha_space PARAMS ((int));
+static void s_alpha_ucons PARAMS ((int));
+static void s_alpha_arch PARAMS ((int));
 
 static void create_literal_section PARAMS ((const char *, segT *, symbolS **));
 #ifndef OBJ_ELF
 static void select_gp_value PARAMS ((void));
 #endif
 static void alpha_align PARAMS ((int, char *, symbolS *, int));
-
-#ifdef RELOC_OP_P
-static void alpha_adjust_symtab_relocs PARAMS ((bfd *, asection *, PTR));
-#endif
-
 \f
 /* Generic assembler global variables which must be defined by all
    targets.  */
@@ -309,11 +325,11 @@ const char *md_shortopts = "Fm:gG:";
 struct option md_longopts[] = {
 #define OPTION_32ADDR (OPTION_MD_BASE)
   { "32addr", no_argument, NULL, OPTION_32ADDR },
-#define OPTION_RELAX (OPTION_32ADDR+1)
+#define OPTION_RELAX (OPTION_32ADDR + 1)
   { "relax", no_argument, NULL, OPTION_RELAX },
 #ifdef OBJ_ELF
-#define OPTION_MDEBUG (OPTION_RELAX+1)
-#define OPTION_NO_MDEBUG (OPTION_MDEBUG+1)
+#define OPTION_MDEBUG (OPTION_RELAX + 1)
+#define OPTION_NO_MDEBUG (OPTION_MDEBUG + 1)
   { "mdebug", no_argument, NULL, OPTION_MDEBUG },
   { "no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG },
 #endif
@@ -321,7 +337,6 @@ struct option md_longopts[] = {
 };
 
 size_t md_longopts_size = sizeof (md_longopts);
-
 \f
 #ifdef OBJ_EVAX
 #define AXP_REG_R0     0
@@ -476,112 +491,83 @@ static int alpha_flag_show_after_trunc = 0;              /* -H */
    that op-O_literal indexes into it.  */
 
 #define ALPHA_RELOC_TABLE(op)                                          \
-&alpha_reloc_op[ ((!USER_RELOC_P (op))                                 \
+(&alpha_reloc_op[ ((!USER_RELOC_P (op))                                        \
                  ? (abort (), 0)                                       \
-                 : (int) (op) - (int) O_literal) ]
+                 : (int) (op) - (int) O_literal) ])
 
-#define LITUSE_BASE    1
-#define LITUSE_BYTOFF  2
-#define LITUSE_JSR     3
+#define DEF(NAME, RELOC, REQ, ALLOW) \
+ { #NAME, sizeof(#NAME)-1, O_##NAME, RELOC, REQ, ALLOW}
 
 static const struct alpha_reloc_op_tag {
   const char *name;                            /* string to lookup */
   size_t length;                               /* size of the string */
-  bfd_reloc_code_real_type reloc;              /* relocation before frob */
   operatorT op;                                        /* which operator to use */
-  int lituse;                                  /* addened to specify lituse */
+  bfd_reloc_code_real_type reloc;              /* relocation before frob */
+  unsigned int require_seq : 1;                        /* require a sequence number */
+  unsigned int allow_seq : 1;                  /* allow a sequence number */
 } alpha_reloc_op[] = {
-
-  {
-    "literal",                                 /* name */
-    sizeof ("literal")-1,                      /* length */
-    BFD_RELOC_ALPHA_USER_LITERAL,              /* reloc */
-    O_literal,                                 /* op */
-    0,                                         /* lituse */
-  },
-
-  {
-    "lituse_base",                             /* name */
-    sizeof ("lituse_base")-1,                  /* length */
-    BFD_RELOC_ALPHA_USER_LITUSE_BASE,          /* reloc */
-    O_lituse_base,                             /* op */
-    LITUSE_BASE,                               /* lituse */
-  },
-
-  {
-    "lituse_bytoff",                           /* name */
-    sizeof ("lituse_bytoff")-1,                        /* length */
-    BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF,                /* reloc */
-    O_lituse_bytoff,                           /* op */
-    LITUSE_BYTOFF,                             /* lituse */
-  },
-
-  {
-    "lituse_jsr",                              /* name */
-    sizeof ("lituse_jsr")-1,                   /* length */
-    BFD_RELOC_ALPHA_USER_LITUSE_JSR,           /* reloc */
-    O_lituse_jsr,                              /* op */
-    LITUSE_JSR,                                        /* lituse */
-  },
-
-  {
-    "gpdisp",                                  /* name */
-    sizeof ("gpdisp")-1,                       /* length */
-    BFD_RELOC_ALPHA_USER_GPDISP,               /* reloc */
-    O_gpdisp,                                  /* op */
-    0,                                         /* lituse */
-  },
-
-  {
-    "gprelhigh",                               /* name */
-    sizeof ("gprelhigh")-1,                    /* length */
-    BFD_RELOC_ALPHA_USER_GPRELHIGH,            /* reloc */
-    O_gprelhigh,                               /* op */
-    0,                                         /* lituse */
-  },
-
-  {
-    "gprellow",                                        /* name */
-    sizeof ("gprellow")-1,                     /* length */
-    BFD_RELOC_ALPHA_USER_GPRELLOW,             /* reloc */
-    O_gprellow,                                        /* op */
-    0,                                         /* lituse */
-  },
+  DEF(literal, BFD_RELOC_ALPHA_ELF_LITERAL, 0, 1),
+  DEF(lituse_addr, DUMMY_RELOC_LITUSE_ADDR, 1, 1),
+  DEF(lituse_base, DUMMY_RELOC_LITUSE_BASE, 1, 1),
+  DEF(lituse_bytoff, DUMMY_RELOC_LITUSE_BYTOFF, 1, 1),
+  DEF(lituse_jsr, DUMMY_RELOC_LITUSE_JSR, 1, 1),
+  DEF(lituse_tlsgd, DUMMY_RELOC_LITUSE_TLSGD, 1, 1),
+  DEF(lituse_tlsldm, DUMMY_RELOC_LITUSE_TLSLDM, 1, 1),
+  DEF(gpdisp, BFD_RELOC_ALPHA_GPDISP, 1, 1),
+  DEF(gprelhigh, BFD_RELOC_ALPHA_GPREL_HI16, 0, 0),
+  DEF(gprellow, BFD_RELOC_ALPHA_GPREL_LO16, 0, 0),
+  DEF(gprel, BFD_RELOC_GPREL16, 0, 0),
+  DEF(samegp, BFD_RELOC_ALPHA_BRSGP, 0, 0),
+  DEF(tlsgd, BFD_RELOC_ALPHA_TLSGD, 0, 1),
+  DEF(tlsldm, BFD_RELOC_ALPHA_TLSLDM, 0, 1),
+  DEF(gotdtprel, BFD_RELOC_ALPHA_GOTDTPREL16, 0, 0),
+  DEF(dtprelhi, BFD_RELOC_ALPHA_DTPREL_HI16, 0, 0),
+  DEF(dtprello, BFD_RELOC_ALPHA_DTPREL_LO16, 0, 0),
+  DEF(dtprel, BFD_RELOC_ALPHA_DTPREL16, 0, 0),
+  DEF(gottprel, BFD_RELOC_ALPHA_GOTTPREL16, 0, 0),
+  DEF(tprelhi, BFD_RELOC_ALPHA_TPREL_HI16, 0, 0),
+  DEF(tprello, BFD_RELOC_ALPHA_TPREL_LO16, 0, 0),
+  DEF(tprel, BFD_RELOC_ALPHA_TPREL16, 0, 0),
 };
 
+#undef DEF
+
 static const int alpha_num_reloc_op
   = sizeof (alpha_reloc_op) / sizeof (*alpha_reloc_op);
+#endif /* RELOC_OP_P */
 
 /* Maximum # digits needed to hold the largest sequence # */
 #define ALPHA_RELOC_DIGITS 25
 
-/* Whether a sequence number is valid.  */
-#define ALPHA_RELOC_SEQUENCE_OK(X) ((X) > 0 && ((unsigned) (X)) == (X))
-
 /* Structure to hold explict sequence information.  */
-struct alpha_literal_tag
+struct alpha_reloc_tag
 {
-  fixS *lituse;                        /* head of linked list of !literals */
+  fixS *master;                        /* the literal reloc */
+  fixS *slaves;                        /* head of linked list of lituses */
   segT segment;                        /* segment relocs are in or undefined_section*/
-  int multi_section_p;         /* True if more than one section was used */
-  unsigned sequence;           /* sequence # */
-  unsigned n_literals;         /* # of literals */
-  unsigned n_lituses;          /* # of lituses */
+  long sequence;               /* sequence # */
+  unsigned n_master;           /* # of literals */
+  unsigned n_slaves;           /* # of lituses */
+  unsigned saw_tlsgd : 1;      /* true if ... */
+  unsigned saw_tlsldm : 1;
+  unsigned saw_lu_tlsgd : 1;
+  unsigned saw_lu_tlsldm : 1;
+  unsigned multi_section_p : 1;        /* true if more than one section was used */
   char string[1];              /* printable form of sequence to hash with */
 };
 
 /* Hash table to link up literals with the appropriate lituse */
 static struct hash_control *alpha_literal_hash;
-#endif
+
+/* Sequence numbers for internal use by macros.  */
+static long next_sequence_num = -1;
 \f
 /* A table of CPU names and opcode sets.  */
 
-static const struct cpu_type
-{
+static const struct cpu_type {
   const char *name;
   unsigned flags;
-} cpu_types[] =
-{
+} cpu_types[] = {
   /* Ad hoc convention: cpu number gets palcode, process code doesn't.
      This supports usage under DU 4.0b that does ".arch ev4", and
      usage in MILO that does -m21064.  Probably something more
@@ -615,48 +601,48 @@ static const struct cpu_type
 static const struct alpha_macro alpha_macros[] = {
 /* Load/Store macros */
   { "lda",     emit_lda, NULL,
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_LITERAL, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "ldah",    emit_ldah, NULL,
     { MACRO_IR, MACRO_EXP, MACRO_EOA } },
 
   { "ldl",     emit_ir_load, "ldl",
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "ldl_l",   emit_ir_load, "ldl_l",
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "ldq",     emit_ir_load, "ldq",
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_LITERAL, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "ldq_l",   emit_ir_load, "ldq_l",
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "ldq_u",   emit_ir_load, "ldq_u",
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "ldf",     emit_loadstore, "ldf",
-    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "ldg",     emit_loadstore, "ldg",
-    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "lds",     emit_loadstore, "lds",
-    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "ldt",     emit_loadstore, "ldt",
-    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
 
   { "ldb",     emit_ldX, (PTR) 0,
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "ldbu",    emit_ldXu, (PTR) 0,
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "ldw",     emit_ldX, (PTR) 1,
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "ldwu",    emit_ldXu, (PTR) 1,
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
 
   { "uldw",    emit_uldX, (PTR) 1,
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "uldwu",   emit_uldXu, (PTR) 1,
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "uldl",    emit_uldX, (PTR) 2,
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "uldlu",   emit_uldXu, (PTR) 2,
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "uldq",    emit_uldXu, (PTR) 3,
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
 
   { "ldgp",    emit_ldgp, NULL,
     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA } },
@@ -681,34 +667,34 @@ static const struct alpha_macro alpha_macros[] = {
 #endif
 
   { "stl",     emit_loadstore, "stl",
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "stl_c",   emit_loadstore, "stl_c",
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "stq",     emit_loadstore, "stq",
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "stq_c",   emit_loadstore, "stq_c",
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "stq_u",   emit_loadstore, "stq_u",
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "stf",     emit_loadstore, "stf",
-    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "stg",     emit_loadstore, "stg",
-    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "sts",     emit_loadstore, "sts",
-    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "stt",     emit_loadstore, "stt",
-    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
 
   { "stb",     emit_stX, (PTR) 0,
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "stw",     emit_stX, (PTR) 1,
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "ustw",    emit_ustX, (PTR) 1,
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "ustl",    emit_ustX, (PTR) 2,
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
   { "ustq",    emit_ustX, (PTR) 3,
-    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
+    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
 
 /* Arithmetic macros */
 #if 0
@@ -771,15 +757,15 @@ static const struct alpha_macro alpha_macros[] = {
       MACRO_IR, MACRO_EXP, MACRO_EOA */ } },
 
   { "jsr",     emit_jsrjmp, "jsr",
-    { MACRO_PIR, MACRO_EXP, MACRO_JSR, MACRO_EOA,
-      MACRO_PIR, MACRO_JSR, MACRO_EOA,
-      MACRO_IR,  MACRO_EXP, MACRO_JSR, MACRO_EOA,
-      MACRO_EXP, MACRO_JSR, MACRO_EOA } },
+    { MACRO_PIR, MACRO_EXP, MACRO_EOA,
+      MACRO_PIR, MACRO_EOA,
+      MACRO_IR,  MACRO_EXP, MACRO_EOA,
+      MACRO_EXP, MACRO_EOA } },
   { "jmp",     emit_jsrjmp, "jmp",
-    { MACRO_PIR, MACRO_EXP, MACRO_JSR, MACRO_EOA,
-      MACRO_PIR, MACRO_JSR, MACRO_EOA,
-      MACRO_IR,  MACRO_EXP, MACRO_JSR, MACRO_EOA,
-      MACRO_EXP, MACRO_JSR, MACRO_EOA } },
+    { MACRO_PIR, MACRO_EXP, MACRO_EOA,
+      MACRO_PIR, MACRO_EOA,
+      MACRO_IR,  MACRO_EXP, MACRO_EOA,
+      MACRO_EXP, MACRO_EOA } },
   { "ret",     emit_retjcr, "ret",
     { MACRO_IR, MACRO_EXP, MACRO_EOA,
       MACRO_IR, MACRO_EOA,
@@ -827,14 +813,15 @@ md_begin ()
   /* Create the opcode hash table */
 
   alpha_opcode_hash = hash_new ();
-  for (i = 0; i < alpha_num_opcodes; )
+  for (i = 0; i < alpha_num_opcodes;)
     {
       const char *name, *retval, *slash;
 
       name = alpha_opcodes[i].name;
-      retval = hash_insert (alpha_opcode_hash, name, (PTR)&alpha_opcodes[i]);
+      retval = hash_insert (alpha_opcode_hash, name, (PTR) &alpha_opcodes[i]);
       if (retval)
-       as_fatal (_("internal error: can't hash opcode `%s': %s"), name, retval);
+       as_fatal (_("internal error: can't hash opcode `%s': %s"),
+                 name, retval);
 
       /* Some opcodes include modifiers of various sorts with a "/mod"
         syntax, like the architecture manual suggests.  However, for
@@ -847,7 +834,7 @@ md_begin ()
          memcpy (p, name, slash - name);
          strcpy (p + (slash - name), slash + 1);
 
-         (void) hash_insert (alpha_opcode_hash, p, (PTR)&alpha_opcodes[i]);
+         (void) hash_insert (alpha_opcode_hash, p, (PTR) &alpha_opcodes[i]);
          /* Ignore failures -- the opcode table does duplicate some
             variants in different forms, like "hw_stq" and "hw_st/q".  */
        }
@@ -861,14 +848,15 @@ md_begin ()
   /* Create the macro hash table */
 
   alpha_macro_hash = hash_new ();
-  for (i = 0; i < alpha_num_macros; )
+  for (i = 0; i < alpha_num_macros;)
     {
       const char *name, *retval;
 
       name = alpha_macros[i].name;
-      retval = hash_insert (alpha_macro_hash, name, (PTR)&alpha_macros[i]);
+      retval = hash_insert (alpha_macro_hash, name, (PTR) &alpha_macros[i]);
       if (retval)
-       as_fatal (_("internal error: can't hash macro `%s': %s"), name, retval);
+       as_fatal (_("internal error: can't hash macro `%s': %s"),
+                 name, retval);
 
       while (++i < alpha_num_macros
             && (alpha_macros[i].name == name
@@ -888,7 +876,7 @@ md_begin ()
   for (; i < 64; ++i)
     {
       char name[5];
-      sprintf (name, "$f%d", i-32);
+      sprintf (name, "$f%d", i - 32);
       alpha_register_table[i] = symbol_create (name, reg_section, i,
                                               &zero_address_frag);
     }
@@ -915,17 +903,15 @@ md_begin ()
   if (ECOFF_DEBUGGING)
     {
       segT sec = subseg_new (".mdebug", (subsegT) 0);
-      bfd_set_section_flags (stdoutput, sec, SEC_HAS_CONTENTS|SEC_READONLY);
+      bfd_set_section_flags (stdoutput, sec, SEC_HAS_CONTENTS | SEC_READONLY);
       bfd_set_section_alignment (stdoutput, sec, 3);
     }
 #endif /* OBJ_ELF */
 
-  subseg_set (text_section, 0);
-
-#ifdef RELOC_OP_P
   /* Create literal lookup hash table.  */
   alpha_literal_hash = hash_new ();
-#endif
+
+  subseg_set (text_section, 0);
 }
 
 /* The public interface to the instruction assembler.  */
@@ -1166,13 +1152,14 @@ md_pcrel_from (fixP)
    the distance to the "lda" instruction for setting the addend to
    GPDISP.  */
 
-int
-md_apply_fix (fixP, valueP)
+void
+md_apply_fix3 (fixP, valP, seg)
      fixS *fixP;
-     valueT *valueP;
+     valueT * valP;
+     segT seg;
 {
   char * const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
-  valueT value = *valueP;
+  valueT value = * valP;
   unsigned image, size;
 
   switch (fixP->fx_r_type)
@@ -1184,10 +1171,13 @@ md_apply_fix (fixP, valueP)
     case BFD_RELOC_ALPHA_GPDISP_HI16:
       {
        fixS *next = fixP->fx_next;
-       assert (next->fx_r_type == BFD_RELOC_ALPHA_GPDISP_LO16);
 
-       fixP->fx_offset = (next->fx_frag->fr_address + next->fx_where
-                          - fixP->fx_frag->fr_address - fixP->fx_where);
+       /* With user-specified !gpdisp relocations, we can be missing
+          the matching LO16 reloc.  We will have already issued an
+          error message.  */
+       if (next)
+         fixP->fx_offset = (next->fx_frag->fr_address + next->fx_where
+                            - fixP->fx_frag->fr_address - fixP->fx_where);
 
        value = (value - sign_extend_16 (value)) >> 16;
       }
@@ -1204,7 +1194,7 @@ md_apply_fix (fixP, valueP)
 #endif
 
     do_reloc_gp:
-      fixP->fx_addsy = section_symbol (now_seg);
+      fixP->fx_addsy = section_symbol (seg);
       md_number_to_chars (fixpos, value, 2);
       break;
 
@@ -1228,7 +1218,7 @@ md_apply_fix (fixP, valueP)
          md_number_to_chars (fixpos, value, size);
          goto done;
        }
-      return 1;
+      return;
 
 #ifdef OBJ_ECOFF
     case BFD_RELOC_GPREL32:
@@ -1237,11 +1227,13 @@ md_apply_fix (fixP, valueP)
       /* FIXME: inherited this obliviousness of `value' -- why? */
       md_number_to_chars (fixpos, -alpha_gp_value, 4);
       break;
-#endif
-#ifdef OBJ_ELF
+#else
     case BFD_RELOC_GPREL32:
-      return 1;
 #endif
+    case BFD_RELOC_GPREL16:
+    case BFD_RELOC_ALPHA_GPREL_HI16:
+    case BFD_RELOC_ALPHA_GPREL_LO16:
+      return;
 
     case BFD_RELOC_23_PCREL_S2:
       if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0)
@@ -1250,7 +1242,7 @@ md_apply_fix (fixP, valueP)
          image = (image & ~0x1FFFFF) | ((value >> 2) & 0x1FFFFF);
          goto write_done;
        }
-      return 1;
+      return;
 
     case BFD_RELOC_ALPHA_HINT:
       if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0)
@@ -1259,43 +1251,37 @@ md_apply_fix (fixP, valueP)
          image = (image & ~0x3FFF) | ((value >> 2) & 0x3FFF);
          goto write_done;
        }
-      return 1;
+      return;
+
+#ifdef OBJ_ELF
+    case BFD_RELOC_ALPHA_BRSGP:
+    case BFD_RELOC_ALPHA_TLSGD:
+    case BFD_RELOC_ALPHA_TLSLDM:
+    case BFD_RELOC_ALPHA_GOTDTPREL16:
+    case BFD_RELOC_ALPHA_DTPREL_HI16:
+    case BFD_RELOC_ALPHA_DTPREL_LO16:
+    case BFD_RELOC_ALPHA_DTPREL16:
+    case BFD_RELOC_ALPHA_GOTTPREL16:
+    case BFD_RELOC_ALPHA_TPREL_HI16:
+    case BFD_RELOC_ALPHA_TPREL_LO16:
+    case BFD_RELOC_ALPHA_TPREL16:
+      return;
+#endif
 
 #ifdef OBJ_ECOFF
     case BFD_RELOC_ALPHA_LITERAL:
       md_number_to_chars (fixpos, value, 2);
-      return 1;
-
-    case BFD_RELOC_ALPHA_LITUSE:
-      return 1;
+      return;
 #endif
-#ifdef OBJ_ELF
     case BFD_RELOC_ALPHA_ELF_LITERAL:
     case BFD_RELOC_ALPHA_LITUSE:
-      return 1;
-#endif
-#ifdef OBJ_EVAX
     case BFD_RELOC_ALPHA_LINKAGE:
     case BFD_RELOC_ALPHA_CODEADDR:
-      return 1;
-#endif
-
-#ifdef RELOC_OP_P
-    case BFD_RELOC_ALPHA_USER_LITERAL:
-    case BFD_RELOC_ALPHA_USER_LITUSE_BASE:
-    case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF:
-    case BFD_RELOC_ALPHA_USER_LITUSE_JSR:
-      return 1;
-
-    case BFD_RELOC_ALPHA_USER_GPDISP:
-    case BFD_RELOC_ALPHA_USER_GPRELHIGH:
-    case BFD_RELOC_ALPHA_USER_GPRELLOW:
-      abort ();
-#endif
+      return;
 
     case BFD_RELOC_VTABLE_INHERIT:
     case BFD_RELOC_VTABLE_ENTRY:
-      return 1;
+      return;
 
     default:
       {
@@ -1325,11 +1311,11 @@ md_apply_fix (fixP, valueP)
     }
 
   if (fixP->fx_addsy != 0 || fixP->fx_pcrel != 0)
-    return 1;
+    return;
   else
     {
       as_warn_where (fixP->fx_file, fixP->fx_line,
-                   _("type %d reloc done?\n"), (int) fixP->fx_r_type);
+                    _("type %d reloc done?\n"), (int) fixP->fx_r_type);
       goto done;
     }
 
@@ -1338,12 +1324,9 @@ write_done:
 
 done:
   fixP->fx_done = 1;
-  return 0;
 }
 
-/*
- * Look for a register name in the given symbol.
- */
+/* Look for a register name in the given symbol.  */
 
 symbolS *
 md_undefined_symbol (name)
@@ -1362,7 +1345,7 @@ md_undefined_symbol (name)
          /* FALLTHRU */
 
        case 'r':
-         if (!isdigit (*++name))
+         if (!ISDIGIT (*++name))
            break;
          /* FALLTHRU */
 
@@ -1370,7 +1353,7 @@ md_undefined_symbol (name)
        case '5': case '6': case '7': case '8': case '9':
          if (name[1] == '\0')
            num = name[0] - '0';
-         else if (name[0] != '0' && isdigit (name[1]) && name[2] == '\0')
+         else if (name[0] != '0' && ISDIGIT (name[1]) && name[2] == '\0')
            {
              num = (name[0] - '0') * 10 + name[1] - '0';
              if (num >= 32)
@@ -1430,8 +1413,51 @@ alpha_define_label (sym)
   alpha_insn_label = sym;
 }
 
+/* If we have a BRSGP reloc to a local symbol, adjust it to BRADDR and
+   let it get resolved at assembly time.  */
+
+void
+alpha_validate_fix (f)
+     fixS *f;
+{
+#ifdef OBJ_ELF
+  int offset = 0;
+  const char *name;
+
+  if (f->fx_r_type != BFD_RELOC_ALPHA_BRSGP)
+    return;
+
+  if (! S_IS_DEFINED (f->fx_addsy))
+    return;
+
+  switch (S_GET_OTHER (f->fx_addsy) & STO_ALPHA_STD_GPLOAD)
+    {
+    case STO_ALPHA_NOPV:
+      break;
+    case STO_ALPHA_STD_GPLOAD:
+      offset = 8;
+      break;
+    default:
+      if (S_IS_LOCAL (f->fx_addsy))
+       name = "<local>";
+      else
+       name = S_GET_NAME (f->fx_addsy);
+      as_bad_where (f->fx_file, f->fx_line,
+                   _("!samegp reloc against symbol without .prologue: %s"),
+                   name);
+      break;
+    }
+
+  if (! (S_IS_EXTERN (f->fx_addsy) || S_IS_WEAK (f->fx_addsy)))
+    {
+      f->fx_r_type = BFD_RELOC_23_PCREL_S2;
+      f->fx_offset += offset;
+    }
+#endif
+}
+
 /* Return true if we must always emit a reloc for a type and false if
-   there is some hope of resolving it a assembly time.  */
+   there is some hope of resolving it at assembly time.  */
 
 int
 alpha_force_relocation (f)
@@ -1445,29 +1471,28 @@ alpha_force_relocation (f)
     case BFD_RELOC_ALPHA_GPDISP_HI16:
     case BFD_RELOC_ALPHA_GPDISP_LO16:
     case BFD_RELOC_ALPHA_GPDISP:
-#ifdef OBJ_ECOFF
     case BFD_RELOC_ALPHA_LITERAL:
-#endif
-#ifdef OBJ_ELF
     case BFD_RELOC_ALPHA_ELF_LITERAL:
-#endif
     case BFD_RELOC_ALPHA_LITUSE:
+    case BFD_RELOC_GPREL16:
     case BFD_RELOC_GPREL32:
-#ifdef OBJ_EVAX
+    case BFD_RELOC_ALPHA_GPREL_HI16:
+    case BFD_RELOC_ALPHA_GPREL_LO16:
     case BFD_RELOC_ALPHA_LINKAGE:
     case BFD_RELOC_ALPHA_CODEADDR:
-#endif
-#ifdef RELOC_OP_P
-    case BFD_RELOC_ALPHA_USER_LITERAL:
-    case BFD_RELOC_ALPHA_USER_LITUSE_BASE:
-    case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF:
-    case BFD_RELOC_ALPHA_USER_LITUSE_JSR:
-    case BFD_RELOC_ALPHA_USER_GPDISP:
-    case BFD_RELOC_ALPHA_USER_GPRELHIGH:
-    case BFD_RELOC_ALPHA_USER_GPRELLOW:
-#endif
+    case BFD_RELOC_ALPHA_BRSGP:
     case BFD_RELOC_VTABLE_INHERIT:
     case BFD_RELOC_VTABLE_ENTRY:
+    case BFD_RELOC_ALPHA_TLSGD:
+    case BFD_RELOC_ALPHA_TLSLDM:
+    case BFD_RELOC_ALPHA_GOTDTPREL16:
+    case BFD_RELOC_ALPHA_DTPREL_HI16:
+    case BFD_RELOC_ALPHA_DTPREL_LO16:
+    case BFD_RELOC_ALPHA_DTPREL16:
+    case BFD_RELOC_ALPHA_GOTTPREL16:
+    case BFD_RELOC_ALPHA_TPREL_HI16:
+    case BFD_RELOC_ALPHA_TPREL_LO16:
+    case BFD_RELOC_ALPHA_TPREL16:
       return 1;
 
     case BFD_RELOC_23_PCREL_S2:
@@ -1477,7 +1502,6 @@ alpha_force_relocation (f)
       return 0;
 
     default:
-      assert ((int) f->fx_r_type < 0 && -(int) f->fx_r_type < (int) alpha_num_operands);
       return 0;
     }
 }
@@ -1501,46 +1525,45 @@ alpha_fix_adjustable (f)
     case BFD_RELOC_ALPHA_GPDISP_HI16:
     case BFD_RELOC_ALPHA_GPDISP_LO16:
     case BFD_RELOC_ALPHA_GPDISP:
+    case BFD_RELOC_ALPHA_BRSGP:
       return 0;
 
-#ifdef OBJ_ECOFF
     case BFD_RELOC_ALPHA_LITERAL:
-#endif
-#ifdef OBJ_ELF
     case BFD_RELOC_ALPHA_ELF_LITERAL:
-#endif
-#ifdef RELOC_OP_P
-    case BFD_RELOC_ALPHA_USER_LITERAL:
-#endif
-#ifdef OBJ_EVAX
+    case BFD_RELOC_ALPHA_LITUSE:
     case BFD_RELOC_ALPHA_LINKAGE:
     case BFD_RELOC_ALPHA_CODEADDR:
-#endif
       return 1;
 
-    case BFD_RELOC_ALPHA_LITUSE:
-#ifdef RELOC_OP_P
-    case BFD_RELOC_ALPHA_USER_LITUSE_BASE:
-    case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF:
-    case BFD_RELOC_ALPHA_USER_LITUSE_JSR:
-    case BFD_RELOC_ALPHA_USER_GPDISP:
-    case BFD_RELOC_ALPHA_USER_GPRELHIGH:
-    case BFD_RELOC_ALPHA_USER_GPRELLOW:
-#endif
     case BFD_RELOC_VTABLE_ENTRY:
     case BFD_RELOC_VTABLE_INHERIT:
       return 0;
 
+    case BFD_RELOC_GPREL16:
     case BFD_RELOC_GPREL32:
+    case BFD_RELOC_ALPHA_GPREL_HI16:
+    case BFD_RELOC_ALPHA_GPREL_LO16:
     case BFD_RELOC_23_PCREL_S2:
     case BFD_RELOC_32:
     case BFD_RELOC_64:
     case BFD_RELOC_ALPHA_HINT:
       return 1;
 
+    case BFD_RELOC_ALPHA_TLSGD:
+    case BFD_RELOC_ALPHA_TLSLDM:
+    case BFD_RELOC_ALPHA_GOTDTPREL16:
+    case BFD_RELOC_ALPHA_DTPREL_HI16:
+    case BFD_RELOC_ALPHA_DTPREL_LO16:
+    case BFD_RELOC_ALPHA_DTPREL16:
+    case BFD_RELOC_ALPHA_GOTTPREL16:
+    case BFD_RELOC_ALPHA_TPREL_HI16:
+    case BFD_RELOC_ALPHA_TPREL_LO16:
+    case BFD_RELOC_ALPHA_TPREL16:
+      /* ??? No idea why we can't return a reference to .tbss+10, but
+        we're preventing this in the other assemblers.  Follow for now.  */
+      return 0;
+
     default:
-      assert ((int) f->fx_r_type < 0
-             && - (int) f->fx_r_type < (int) alpha_num_operands);
       return 1;
     }
   /*NOTREACHED*/
@@ -1598,7 +1621,9 @@ tc_gen_reloc (sec, fixp)
        * 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_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy))
+      if ((S_IS_EXTERN (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
@@ -1656,30 +1681,45 @@ alpha_frob_file_before_adjust ()
 
 #endif /* OBJ_ECOFF */
 \f
-#ifdef RELOC_OP_P
+static struct alpha_reloc_tag *
+get_alpha_reloc_tag (sequence)
+     long sequence;
+{
+  char buffer[ALPHA_RELOC_DIGITS];
+  struct alpha_reloc_tag *info;
 
-/* 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.
-   */
+  sprintf (buffer, "!%ld", sequence);
 
-void
-alpha_adjust_symtab ()
-{
-  if (alpha_literal_hash)
+  info = (struct alpha_reloc_tag *) hash_find (alpha_literal_hash, buffer);
+  if (! info)
     {
-#ifdef DEBUG2_ALPHA
-      fprintf (stderr, "alpha_adjust_symtab called\n");
-#endif
+      size_t len = strlen (buffer);
+      const char *errmsg;
+
+      info = (struct alpha_reloc_tag *)
+       xcalloc (sizeof (struct alpha_reloc_tag) + len, 1);
 
-      /* Go over each section, reordering the relocations so that all of the
-         explicit LITUSE's are adjacent to the explicit LITERAL's */
-      bfd_map_over_sections (stdoutput, alpha_adjust_symtab_relocs, (char *) 0);
+      info->segment = now_seg;
+      info->sequence = sequence;
+      strcpy (info->string, buffer);
+      errmsg = hash_insert (alpha_literal_hash, info->string, (PTR) info);
+      if (errmsg)
+       as_fatal (errmsg);
     }
+
+  return info;
 }
 
-\f
-/* Inner function to move LITUSE's next to the LITERAL.  */
+/* Before the relocations are written, reorder them, so that user
+   supplied !lituse relocations follow the appropriate !literal
+   relocations, and similarly for !gpdisp relocations.  */
+
+void
+alpha_adjust_symtab ()
+{
+  if (alpha_literal_hash)
+    bfd_map_over_sections (stdoutput, alpha_adjust_symtab_relocs, NULL);
+}
 
 static void
 alpha_adjust_symtab_relocs (abfd, sec, ptr)
@@ -1691,17 +1731,11 @@ alpha_adjust_symtab_relocs (abfd, sec, ptr)
   fixS **prevP;
   fixS *fixp;
   fixS *next;
-  fixS *lituse;
-  int n_lituses = 0;
-
-#ifdef DEBUG2_ALPHA
-  int n = 0;
-  int n_literals = 0;
-  int n_dup_literals = 0;
-#endif
+  fixS *slave;
 
-  /* If seginfo is NULL, we did not create this section; don't do anything with
-     it.  By using a pointer to a pointer, we can update the links in place.  */
+  /* If seginfo is NULL, we did not create this section; don't do
+     anything with it.  By using a pointer to a pointer, we can update
+     the links in place.  */
   if (seginfo == NULL)
     return;
 
@@ -1709,122 +1743,133 @@ alpha_adjust_symtab_relocs (abfd, sec, ptr)
   if (! seginfo->fix_root)
     return;
 
-  /* First rebuild the fixup chain without the expicit lituse's.  */
-  prevP = &(seginfo->fix_root);
+  /* First rebuild the fixup chain without the expicit lituse and
+     gpdisp_lo16 relocs.  */
+  prevP = &seginfo->fix_root;
   for (fixp = seginfo->fix_root; fixp; fixp = next)
     {
       next = fixp->fx_next;
       fixp->fx_next = (fixS *) 0;
-#ifdef DEBUG2_ALPHA
-      n++;
-#endif
 
       switch (fixp->fx_r_type)
        {
-       default:
-         *prevP = fixp;
-         prevP = &(fixp->fx_next);
-#ifdef DEBUG2_ALPHA
-         fprintf (stderr,
-                  "alpha_adjust_symtab_relocs: 0x%lx, other relocation %s\n",
-                  (long) fixp,
-                  bfd_get_reloc_code_name (fixp->fx_r_type));
-#endif
-         break;
-
-       case BFD_RELOC_ALPHA_USER_LITERAL:
-         *prevP = fixp;
-         prevP = &(fixp->fx_next);
-         /* prevent assembler from trying to adjust the offset */
-#ifdef DEBUG2_ALPHA
-         n_literals++;
-         if (fixp->tc_fix_data.info->n_literals != 1)
-           n_dup_literals++;
-         fprintf (stderr,
-                  "alpha_adjust_symtab_relocs: 0x%lx, !literal!%.6d, # literals = %2d\n",
-                  (long) fixp,
-                  fixp->tc_fix_data.info->sequence,
-                  fixp->tc_fix_data.info->n_literals);
-#endif
+       case BFD_RELOC_ALPHA_LITUSE:
+         if (fixp->tc_fix_data.info->n_master == 0)
+           as_bad_where (fixp->fx_file, fixp->fx_line,
+                         _("No !literal!%ld was found"),
+                         fixp->tc_fix_data.info->sequence);
+         if (fixp->fx_offset == LITUSE_TLSGD)
+           {
+             if (! fixp->tc_fix_data.info->saw_tlsgd)
+               as_bad_where (fixp->fx_file, fixp->fx_line,
+                             _("No !tlsgd!%ld was found"),
+                             fixp->tc_fix_data.info->sequence);
+           }
+         else if (fixp->fx_offset == LITUSE_TLSLDM)
+           {
+             if (! fixp->tc_fix_data.info->saw_tlsldm)
+               as_bad_where (fixp->fx_file, fixp->fx_line,
+                             _("No !tlsldm!%ld was found"),
+                             fixp->tc_fix_data.info->sequence);
+           }
          break;
 
-         /* do not link in lituse's */
-       case BFD_RELOC_ALPHA_USER_LITUSE_BASE:
-       case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF:
-       case BFD_RELOC_ALPHA_USER_LITUSE_JSR:
-         n_lituses++;
-         if (fixp->tc_fix_data.info->n_literals == 0)
+       case BFD_RELOC_ALPHA_GPDISP_LO16:
+         if (fixp->tc_fix_data.info->n_master == 0)
            as_bad_where (fixp->fx_file, fixp->fx_line,
-                         _("No !literal!%d was found"),
+                         _("No ldah !gpdisp!%ld was found"),
                          fixp->tc_fix_data.info->sequence);
-#ifdef DEBUG2_ALPHA
-         fprintf (stderr,
-                  "alpha_adjust_symtab_relocs: 0x%lx, !lituse !%.6d, # lituses  = %2d, next_lituse = 0x%lx\n",
-                  (long) fixp,
-                  fixp->tc_fix_data.info->sequence,
-                  fixp->tc_fix_data.info->n_lituses,
-                  (long) fixp->tc_fix_data.next_lituse);
-#endif
+         break;
+
+       case BFD_RELOC_ALPHA_ELF_LITERAL:
+         if (fixp->tc_fix_data.info->saw_tlsgd
+             || fixp->tc_fix_data.info->saw_tlsldm)
+           break;
+         /* FALLTHRU */
+
+       default:
+         *prevP = fixp;
+         prevP = &fixp->fx_next;
          break;
        }
     }
 
-  /* If there were any lituses, go and add them to the chain, unless there is
-     more than one !literal for a given sequence number.  They are linked
-     through the next_lituse field in reverse order, so as we go through the
-     next_lituse chain, we effectively reverse the chain once again.  If there
-     was more than one !literal, we fall back to loading up the address w/o
-     optimization.  Also, if the !literals/!lituses are spread in different
-     segments (happens in the Linux kernel semaphores), suppress the
-     optimization.  */
-  if (n_lituses)
+  /* Go back and re-chain dependent relocations.  They are currently
+     linked through the next_reloc field in reverse order, so as we
+     go through the next_reloc chain, we effectively reverse the chain
+     once again.
+
+     Except if there is more than one !literal for a given sequence
+     number.  In that case, the programmer and/or compiler is not sure
+     how control flows from literal to lituse, and we can't be sure to
+     get the relaxation correct.
+
+     ??? Well, actually we could, if there are enough lituses such that
+     we can make each literal have at least one of each lituse type
+     present.  Not implemented.
+
+     Also suppress the optimization if the !literals/!lituses are spread
+     in different segments.  This can happen with "intersting" uses of
+     inline assembly; examples are present in the Linux kernel semaphores.  */
+
+  for (fixp = seginfo->fix_root; fixp; fixp = next)
     {
-      for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
+      next = fixp->fx_next;
+      switch (fixp->fx_r_type)
        {
-         switch (fixp->fx_r_type)
+       case BFD_RELOC_ALPHA_TLSGD:
+       case BFD_RELOC_ALPHA_TLSLDM:
+         if (!fixp->tc_fix_data.info)
+           break;
+         if (fixp->tc_fix_data.info->n_master == 0)
+           break;
+         else if (fixp->tc_fix_data.info->n_master > 1)
            {
-           default:
+             as_bad_where (fixp->fx_file, fixp->fx_line,
+                           _("too many !literal!%ld for %s"),
+                           fixp->tc_fix_data.info->sequence,
+                           (fixp->fx_r_type == BFD_RELOC_ALPHA_TLSGD
+                            ? "!tlsgd" : "!tlsldm"));
              break;
+           }
 
-           case BFD_RELOC_ALPHA_USER_LITERAL:
-#ifdef OBJ_ELF
-             fixp->fx_r_type = BFD_RELOC_ALPHA_ELF_LITERAL;
-#else
-             fixp->fx_r_type = BFD_RELOC_ALPHA_LITERAL;        /* XXX check this */
-#endif
-             if (fixp->tc_fix_data.info->n_literals == 1
-                 && ! fixp->tc_fix_data.info->multi_section_p)
+         fixp->tc_fix_data.info->master->fx_next = fixp->fx_next;
+         fixp->fx_next = fixp->tc_fix_data.info->master;
+         fixp = fixp->fx_next;
+         /* FALLTHRU */
+
+       case BFD_RELOC_ALPHA_ELF_LITERAL:
+         if (fixp->tc_fix_data.info->n_master == 1
+             && ! fixp->tc_fix_data.info->multi_section_p)
+           {
+             for (slave = fixp->tc_fix_data.info->slaves;
+                  slave != (fixS *) 0;
+                  slave = slave->tc_fix_data.next_reloc)
                {
-                 for (lituse = fixp->tc_fix_data.info->lituse;
-                      lituse != (fixS *) 0;
-                      lituse = lituse->tc_fix_data.next_lituse)
-                   {
-                     lituse->fx_next = fixp->fx_next;
-                     fixp->fx_next = lituse;
-                   }
+                 slave->fx_next = fixp->fx_next;
+                 fixp->fx_next = slave;
                }
-             break;
+           }
+         break;
 
-           case BFD_RELOC_ALPHA_USER_LITUSE_BASE:
-           case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF:
-           case BFD_RELOC_ALPHA_USER_LITUSE_JSR:
-             fixp->fx_r_type = BFD_RELOC_ALPHA_LITUSE;
-             break;
+       case BFD_RELOC_ALPHA_GPDISP_HI16:
+         if (fixp->tc_fix_data.info->n_slaves == 0)
+           as_bad_where (fixp->fx_file, fixp->fx_line,
+                         _("No lda !gpdisp!%ld was found"),
+                         fixp->tc_fix_data.info->sequence);
+         else
+           {
+             slave = fixp->tc_fix_data.info->slaves;
+             slave->fx_next = next;
+             fixp->fx_next = slave;
            }
+         break;
+
+       default:
+         break;
        }
     }
-
-#ifdef DEBUG2_ALPHA
-  fprintf (stderr, "alpha_adjust_symtab_relocs: %s, %d literal%s, %d duplicate literal%s, %d lituse%s\n\n",
-          sec->name,
-          n_literals, (n_literals == 1) ? "" : "s",
-          n_dup_literals, (n_dup_literals == 1) ? "" : "s",
-          n_lituses, (n_lituses == 1) ? "" : "s");
-#endif
 }
-
-#endif /* RELOC_OP_P */
-
 \f
 #ifdef DEBUG_ALPHA
 static void
@@ -1875,19 +1920,27 @@ debug_exp (tok, ntok)
        case O_pregister:               name = "O_pregister";           break;
        case O_cpregister:              name = "O_cpregister";          break;
        case O_literal:                 name = "O_literal";             break;
+       case O_lituse_addr:             name = "O_lituse_addr";         break;
        case O_lituse_base:             name = "O_lituse_base";         break;
        case O_lituse_bytoff:           name = "O_lituse_bytoff";       break;
        case O_lituse_jsr:              name = "O_lituse_jsr";          break;
+       case O_lituse_tlsgd:            name = "O_lituse_tlsgd";        break;
+       case O_lituse_tlsldm:           name = "O_lituse_tlsldm";       break;
        case O_gpdisp:                  name = "O_gpdisp";              break;
        case O_gprelhigh:               name = "O_gprelhigh";           break;
        case O_gprellow:                name = "O_gprellow";            break;
-       case O_md10:                    name = "O_md10";                break;
-       case O_md11:                    name = "O_md11";                break;
-       case O_md12:                    name = "O_md12";                break;
-       case O_md13:                    name = "O_md13";                break;
-       case O_md14:                    name = "O_md14";                break;
-       case O_md15:                    name = "O_md15";                break;
-       case O_md16:                    name = "O_md16";                break;
+       case O_gprel:                   name = "O_gprel";               break;
+       case O_samegp:                  name = "O_samegp";              break;
+       case O_tlsgd:                   name = "O_tlsgd";               break;
+       case O_tlsldm:                  name = "O_tlsldm";              break;
+       case O_gotdtprel:               name = "O_gotdtprel";           break;
+       case O_dtprelhi:                name = "O_dtprelhi";            break;
+       case O_dtprello:                name = "O_dtprello";            break;
+       case O_dtprel:                  name = "O_dtprel";              break;
+       case O_gottprel:                name = "O_gottprel";            break;
+       case O_tprelhi:                 name = "O_tprelhi";             break;
+       case O_tprello:                 name = "O_tprello";             break;
+       case O_tprel:                   name = "O_tprel";               break;
        }
 
       fprintf (stderr, ", %s(%s, %s, %d)", name,
@@ -1914,13 +1967,11 @@ tokenize_arguments (str, tok, ntok)
 #ifdef DEBUG_ALPHA
   expressionS *orig_tok = tok;
 #endif
-#ifdef RELOC_OP_P
   char *p;
   const struct alpha_reloc_op_tag *r;
   int c, i;
   size_t len;
   int reloc_found_p = 0;
-#endif
 
   memset (tok, 0, sizeof (*tok) * ntok);
 
@@ -1928,6 +1979,11 @@ tokenize_arguments (str, tok, ntok)
   old_input_line_pointer = input_line_pointer;
   input_line_pointer = str;
 
+#ifdef RELOC_OP_P
+  /* ??? Wrest control of ! away from the regular expression parser.  */
+  is_end_of_line[(unsigned char) '!'] = 1;
+#endif
+
   while (tok < end_tok && *input_line_pointer)
     {
       SKIP_WHITESPACE ();
@@ -1950,57 +2006,66 @@ tokenize_arguments (str, tok, ntok)
          if (!saw_arg)
            goto err;
 
-         for (p = ++input_line_pointer;
-              ((c = *p) != '!' && c != ';' && c != '#' && c != ','
-               && !is_end_of_line[c]);
-              p++)
-           ;
+         ++input_line_pointer;
+         SKIP_WHITESPACE ();
+         p = input_line_pointer;
+         c = get_symbol_end ();
 
          /* Parse !relocation_type */
-         len = p - input_line_pointer;
+         len = input_line_pointer - p;
          if (len == 0)
            {
              as_bad (_("No relocation operand"));
              goto err_report;
            }
 
-         if (c != '!')
+         r = &alpha_reloc_op[0];
+         for (i = alpha_num_reloc_op - 1; i >= 0; i--, r++)
+           if (len == r->length && memcmp (p, r->name, len) == 0)
+             break;
+         if (i < 0)
            {
-             as_bad (_("No !sequence-number after !%s"), input_line_pointer);
+             as_bad (_("Unknown relocation operand: !%s"), p);
              goto err_report;
            }
 
-         r = &alpha_reloc_op[0];
-         for (i = alpha_num_reloc_op-1; i >= 0; i--, r++)
+         *input_line_pointer = c;
+         SKIP_WHITESPACE ();
+         if (*input_line_pointer != '!')
            {
-             if (len == r->length
-                 && memcmp (input_line_pointer, r->name, len) == 0)
-               break;
+             if (r->require_seq)
+               {
+                 as_bad (_("no sequence number after !%s"), p);
+                 goto err_report;
+               }
+
+             tok->X_add_number = 0;
            }
-         if (i < 0)
+         else
            {
-             as_bad (_("Unknown relocation operand: !%s"), input_line_pointer);
-             goto err_report;
-           }
-
-         input_line_pointer = ++p;
+             if (! r->allow_seq)
+               {
+                 as_bad (_("!%s does not use a sequence number"), p);
+                 goto err_report;
+               }
 
-         /* Parse !sequence_number */
-         memset (tok, '\0', sizeof (expressionS));
-         expression (tok);
+             input_line_pointer++;
 
-         if (tok->X_op != O_constant
-             || ! ALPHA_RELOC_SEQUENCE_OK (tok->X_add_number))
-           {
-             as_bad (_("Bad sequence number: !%s!%s"), r->name, input_line_pointer);
-             goto err_report;
+             /* Parse !sequence_number */
+             expression (tok);
+             if (tok->X_op != O_constant || tok->X_add_number <= 0)
+               {
+                 as_bad (_("Bad sequence number: !%s!%s"),
+                         r->name, input_line_pointer);
+                 goto err_report;
+               }
            }
 
          tok->X_op = r->op;
          reloc_found_p = 1;
          ++tok;
          break;
-#endif
+#endif /* RELOC_OP_P */
 
        case ',':
          ++input_line_pointer;
@@ -2052,18 +2117,25 @@ fini:
 #ifdef DEBUG_ALPHA
   debug_exp (orig_tok, ntok - (end_tok - tok));
 #endif
+#ifdef RELOC_OP_P
+  is_end_of_line[(unsigned char) '!'] = 0;
+#endif
 
   return ntok - (end_tok - tok);
 
 err:
+#ifdef RELOC_OP_P
+  is_end_of_line[(unsigned char) '!'] = 0;
+#endif
   input_line_pointer = old_input_line_pointer;
   return TOKENIZE_ERROR;
 
-#ifdef RELOC_OP_P
 err_report:
+#ifdef RELOC_OP_P
+  is_end_of_line[(unsigned char) '!'] = 0;
+#endif
   input_line_pointer = old_input_line_pointer;
   return TOKENIZE_ERROR_REPORT;
-#endif
 }
 
 /* Search forward through all variants of an opcode looking for a
@@ -2120,12 +2192,12 @@ find_opcode_match (first_opcode, tok, pntok, pcpumatch)
                  || !is_fpr_num (tok[tokidx].X_add_number))
                goto match_failed;
              break;
-           case AXP_OPERAND_IR|AXP_OPERAND_PARENS:
+           case AXP_OPERAND_IR | AXP_OPERAND_PARENS:
              if (tok[tokidx].X_op != O_pregister
                  || !is_ir_num (tok[tokidx].X_add_number))
                goto match_failed;
              break;
-           case AXP_OPERAND_IR|AXP_OPERAND_PARENS|AXP_OPERAND_COMMA:
+           case AXP_OPERAND_IR | AXP_OPERAND_PARENS | AXP_OPERAND_COMMA:
              if (tok[tokidx].X_op != O_cpregister
                  || !is_ir_num (tok[tokidx].X_add_number))
                goto match_failed;
@@ -2164,11 +2236,11 @@ find_opcode_match (first_opcode, tok, pntok, pcpumatch)
 
     match_failed:;
     }
-  while (++opcode-alpha_opcodes < alpha_num_opcodes
+  while (++opcode - alpha_opcodes < alpha_num_opcodes
         && !strcmp (opcode->name, first_opcode->name));
 
   if (*pcpumatch)
-      *pcpumatch = got_cpu_match;
+    *pcpumatch = got_cpu_match;
 
   return NULL;
 }
@@ -2251,7 +2323,6 @@ find_macro_match (first_macro, tok, pntok)
                case O_register:
                case O_pregister:
                case O_cpregister:
-#ifdef RELOC_OP_P
                case O_literal:
                case O_lituse_base:
                case O_lituse_bytoff:
@@ -2259,7 +2330,8 @@ find_macro_match (first_macro, tok, pntok)
                case O_gpdisp:
                case O_gprelhigh:
                case O_gprellow:
-#endif
+               case O_gprel:
+               case O_samegp:
                  goto match_failed;
 
                default:
@@ -2268,38 +2340,6 @@ find_macro_match (first_macro, tok, pntok)
              ++tokidx;
              break;
 
-             /* optional !literal!<number> */
-           case MACRO_LITERAL:
-#ifdef RELOC_OP_P
-             if (tokidx < ntok && tok[tokidx].X_op == O_literal)
-               tokidx++;
-#endif
-             break;
-
-             /* optional !lituse_base!<number> */
-           case MACRO_BASE:
-#ifdef RELOC_OP_P
-             if (tokidx < ntok && tok[tokidx].X_op == O_lituse_base)
-               tokidx++;
-#endif
-             break;
-
-             /* optional !lituse_bytoff!<number> */
-           case MACRO_BYTOFF:
-#ifdef RELOC_OP_P
-             if (tokidx < ntok && tok[tokidx].X_op == O_lituse_bytoff)
-               tokidx++;
-#endif
-             break;
-
-             /* optional !lituse_jsr!<number> */
-           case MACRO_JSR:
-#ifdef RELOC_OP_P
-             if (tokidx < ntok && tok[tokidx].X_op == O_lituse_jsr)
-               tokidx++;
-#endif
-             break;
-
            match_failed:
              while (*arg != MACRO_EOA)
                ++arg;
@@ -2309,7 +2349,7 @@ find_macro_match (first_macro, tok, pntok)
          ++arg;
        }
     }
-  while (++macro-alpha_macros < alpha_num_macros
+  while (++macro - alpha_macros < alpha_num_macros
         && !strcmp (macro->name, first_macro->name));
 
   return NULL;
@@ -2374,12 +2414,15 @@ insert_operand (insn, operand, val, file, line)
  */
 
 static void
-assemble_insn (opcode, tok, ntok, insn)
+assemble_insn (opcode, tok, ntok, insn, reloc)
      const struct alpha_opcode *opcode;
      const expressionS *tok;
      int ntok;
      struct alpha_insn *insn;
+     bfd_reloc_code_real_type reloc;
 {
+  const struct alpha_operand *reloc_operand = NULL;
+  const expressionS *reloc_exp = NULL;
   const unsigned char *argidx;
   unsigned image;
   int tokidx = 0;
@@ -2435,24 +2478,85 @@ assemble_insn (opcode, tok, ntok, insn)
 
        case O_constant:
          image = insert_operand (image, operand, t->X_add_number, NULL, 0);
+         assert (reloc_operand == NULL);
+         reloc_operand = operand;
+         reloc_exp = t;
          break;
 
        default:
-         {
-           struct alpha_fixup *fixup;
+         /* This is only 0 for fields that should contain registers,
+            which means this pattern shouldn't have matched.  */
+         if (operand->default_reloc == 0)
+           abort ();
 
-           if (insn->nfixups >= MAX_INSN_FIXUPS)
-             as_fatal (_("too many fixups"));
+         /* There is one special case for which an insn receives two
+            relocations, and thus the user-supplied reloc does not
+            override the operand reloc.  */
+         if (operand->default_reloc == BFD_RELOC_ALPHA_HINT)
+           {
+             struct alpha_fixup *fixup;
 
-           fixup = &insn->fixups[insn->nfixups++];
+             if (insn->nfixups >= MAX_INSN_FIXUPS)
+               as_fatal (_("too many fixups"));
 
-           fixup->exp = *t;
-           fixup->reloc = operand->default_reloc;
-         }
+             fixup = &insn->fixups[insn->nfixups++];
+             fixup->exp = *t;
+             fixup->reloc = BFD_RELOC_ALPHA_HINT;
+           }
+         else
+           {
+             if (reloc == BFD_RELOC_UNUSED)
+               reloc = operand->default_reloc;
+
+             assert (reloc_operand == NULL);
+             reloc_operand = operand;
+             reloc_exp = t;
+           }
          break;
        }
     }
 
+  if (reloc != BFD_RELOC_UNUSED)
+    {
+      struct alpha_fixup *fixup;
+
+      if (insn->nfixups >= MAX_INSN_FIXUPS)
+       as_fatal (_("too many fixups"));
+
+      /* ??? My but this is hacky.  But the OSF/1 assembler uses the same
+        relocation tag for both ldah and lda with gpdisp.  Choose the
+        correct internal relocation based on the opcode.  */
+      if (reloc == BFD_RELOC_ALPHA_GPDISP)
+       {
+         if (strcmp (opcode->name, "ldah") == 0)
+           reloc = BFD_RELOC_ALPHA_GPDISP_HI16;
+         else if (strcmp (opcode->name, "lda") == 0)
+           reloc = BFD_RELOC_ALPHA_GPDISP_LO16;
+         else
+           as_bad (_("invalid relocation for instruction"));
+       }
+
+      /* 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)
+       {
+         reloc_howto_type *reloc_howto
+           = bfd_reloc_type_lookup (stdoutput, reloc);
+         if (reloc_howto->bitsize != reloc_operand->bits)
+           {
+             as_bad (_("invalid relocation for field"));
+             return;
+           }
+       }
+
+      fixup = &insn->fixups[insn->nfixups++];
+      if (reloc_exp)
+       fixup->exp = *reloc_exp;
+      else
+       fixup->exp.X_op = O_absent;
+      fixup->reloc = reloc;
+    }
+
   insn->insn = image;
 }
 
@@ -2462,12 +2566,12 @@ assemble_insn (opcode, tok, ntok, insn)
 
 static void
 emit_insn (insn)
-    struct alpha_insn *insn;
+     struct alpha_insn *insn;
 {
   char *f;
   int i;
 
-  /* Take care of alignment duties */
+  /* Take care of alignment duties */
   if (alpha_auto_align_on && alpha_current_align < 2)
     alpha_align (2, (char *) NULL, alpha_insn_label, 0);
   if (alpha_current_align > 2)
@@ -2487,12 +2591,9 @@ emit_insn (insn)
     {
       const struct alpha_operand *operand = (const struct alpha_operand *) 0;
       struct alpha_fixup *fixup = &insn->fixups[i];
+      struct alpha_reloc_tag *info = NULL;
       int size, pcrel;
       fixS *fixP;
-#ifdef RELOC_OP_P
-      char buffer[ALPHA_RELOC_DIGITS];
-      struct alpha_literal_tag *info;
-#endif
 
       /* Some fixups are only used internally and so have no howto */
       if ((int) fixup->reloc < 0)
@@ -2501,41 +2602,23 @@ emit_insn (insn)
          size = 4;
          pcrel = ((operand->flags & AXP_OPERAND_RELATIVE) != 0);
        }
-      else switch (fixup->reloc)
+      else if (fixup->reloc > BFD_RELOC_UNUSED
+              || fixup->reloc == BFD_RELOC_ALPHA_GPDISP_HI16
+              || fixup->reloc == BFD_RELOC_ALPHA_GPDISP_LO16)
        {
-#ifdef OBJ_ELF
-         /* These relocation types are only used internally.  */
-       case BFD_RELOC_ALPHA_GPDISP_HI16:
-       case BFD_RELOC_ALPHA_GPDISP_LO16:
          size = 2;
          pcrel = 0;
-         break;
-#endif
-#ifdef RELOC_OP_P
-         /* and these also are internal only relocations */
-       case BFD_RELOC_ALPHA_USER_LITERAL:
-       case BFD_RELOC_ALPHA_USER_LITUSE_BASE:
-       case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF:
-       case BFD_RELOC_ALPHA_USER_LITUSE_JSR:
-       case BFD_RELOC_ALPHA_USER_GPDISP:
-       case BFD_RELOC_ALPHA_USER_GPRELHIGH:
-       case BFD_RELOC_ALPHA_USER_GPRELLOW:
-         size = 2;
-         pcrel = 0;
-         break;
-#endif
-
-       default:
-         {
-           reloc_howto_type *reloc_howto
-             = bfd_reloc_type_lookup (stdoutput, fixup->reloc);
-           assert (reloc_howto);
+       }
+      else
+       {
+         reloc_howto_type *reloc_howto
+           = bfd_reloc_type_lookup (stdoutput, fixup->reloc);
+         assert (reloc_howto);
 
-           size = bfd_get_reloc_size (reloc_howto);
-           pcrel = reloc_howto->pc_relative;
-         }
+         size = bfd_get_reloc_size (reloc_howto);
          assert (size >= 1 && size <= 4);
-         break;
+
+         pcrel = reloc_howto->pc_relative;
        }
 
       fixP = fix_new_exp (frag_now, f - frag_now->fr_literal, size,
@@ -2545,79 +2628,137 @@ emit_insn (insn)
          and copy in the sequence number for the explicit relocations.  */
       switch (fixup->reloc)
        {
-       case BFD_RELOC_ALPHA_GPDISP_LO16:
-#ifdef OBJ_ECOFF
-       case BFD_RELOC_ALPHA_LITERAL:
-#endif
-#ifdef OBJ_ELF
-       case BFD_RELOC_ALPHA_ELF_LITERAL:
-#endif
+       case BFD_RELOC_ALPHA_HINT:
        case BFD_RELOC_GPREL32:
+       case BFD_RELOC_GPREL16:
+       case BFD_RELOC_ALPHA_GPREL_HI16:
+       case BFD_RELOC_ALPHA_GPREL_LO16:
+       case BFD_RELOC_ALPHA_GOTDTPREL16:
+       case BFD_RELOC_ALPHA_DTPREL_HI16:
+       case BFD_RELOC_ALPHA_DTPREL_LO16:
+       case BFD_RELOC_ALPHA_DTPREL16:
+       case BFD_RELOC_ALPHA_GOTTPREL16:
+       case BFD_RELOC_ALPHA_TPREL_HI16:
+       case BFD_RELOC_ALPHA_TPREL_LO16:
+       case BFD_RELOC_ALPHA_TPREL16:
          fixP->fx_no_overflow = 1;
          break;
 
-#ifdef RELOC_OP_P
-       case BFD_RELOC_ALPHA_USER_LITERAL:
+       case BFD_RELOC_ALPHA_GPDISP_HI16:
          fixP->fx_no_overflow = 1;
-         sprintf (buffer, "!%u", insn->sequence[i]);
-         info = ((struct alpha_literal_tag *)
-                 hash_find (alpha_literal_hash, buffer));
+         fixP->fx_addsy = section_symbol (now_seg);
+         fixP->fx_offset = 0;
 
-         if (! info)
-           {
-             size_t len = strlen (buffer);
-             const char *errmsg;
-
-             info = ((struct alpha_literal_tag *)
-                     xcalloc (sizeof (struct alpha_literal_tag) + len, 1));
-
-             info->segment = now_seg;
-             info->sequence = insn->sequence[i];
-             strcpy (info->string, buffer);
-             errmsg = hash_insert (alpha_literal_hash, info->string, (PTR) info);
-             if (errmsg)
-               as_bad (errmsg);
-           }
+         info = get_alpha_reloc_tag (insn->sequence);
+         if (++info->n_master > 1)
+           as_bad (_("too many ldah insns for !gpdisp!%ld"), insn->sequence);
+         if (info->segment != now_seg)
+           as_bad (_("both insns for !gpdisp!%ld must be in the same section"),
+                   insn->sequence);
+         fixP->tc_fix_data.info = info;
+         break;
+
+       case BFD_RELOC_ALPHA_GPDISP_LO16:
+         fixP->fx_no_overflow = 1;
 
-         ++info->n_literals;
+         info = get_alpha_reloc_tag (insn->sequence);
+         if (++info->n_slaves > 1)
+           as_bad (_("too many lda insns for !gpdisp!%ld"), insn->sequence);
+         if (info->segment != now_seg)
+           as_bad (_("both insns for !gpdisp!%ld must be in the same section"),
+                   insn->sequence);
+         fixP->tc_fix_data.info = info;
+         info->slaves = fixP;
+         break;
+
+       case BFD_RELOC_ALPHA_LITERAL:
+       case BFD_RELOC_ALPHA_ELF_LITERAL:
+         fixP->fx_no_overflow = 1;
 
+         if (insn->sequence == 0)
+           break;
+         info = get_alpha_reloc_tag (insn->sequence);
+         info->master = fixP;
+         info->n_master++;
          if (info->segment != now_seg)
            info->multi_section_p = 1;
-
          fixP->tc_fix_data.info = info;
          break;
 
-       case BFD_RELOC_ALPHA_USER_LITUSE_BASE:
-       case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF:
-       case BFD_RELOC_ALPHA_USER_LITUSE_JSR:
-         sprintf (buffer, "!%u", insn->sequence[i]);
-         info = ((struct alpha_literal_tag *)
-                 hash_find (alpha_literal_hash, buffer));
-
-         if (! info)
+       case DUMMY_RELOC_LITUSE_ADDR:
+         fixP->fx_offset = LITUSE_ADDR;
+         goto do_lituse;
+       case DUMMY_RELOC_LITUSE_BASE:
+         fixP->fx_offset = LITUSE_BASE;
+         goto do_lituse;
+       case DUMMY_RELOC_LITUSE_BYTOFF:
+         fixP->fx_offset = LITUSE_BYTOFF;
+         goto do_lituse;
+       case DUMMY_RELOC_LITUSE_JSR:
+         fixP->fx_offset = LITUSE_JSR;
+         goto do_lituse;
+       case DUMMY_RELOC_LITUSE_TLSGD:
+         fixP->fx_offset = LITUSE_TLSGD;
+         goto do_lituse;
+       case DUMMY_RELOC_LITUSE_TLSLDM:
+         fixP->fx_offset = LITUSE_TLSLDM;
+         goto do_lituse;
+       do_lituse:
+         fixP->fx_addsy = section_symbol (now_seg);
+         fixP->fx_r_type = BFD_RELOC_ALPHA_LITUSE;
+
+         info = get_alpha_reloc_tag (insn->sequence);
+         if (fixup->reloc == DUMMY_RELOC_LITUSE_TLSGD)
+           info->saw_lu_tlsgd = 1;
+         else if (fixup->reloc == DUMMY_RELOC_LITUSE_TLSLDM)
+           info->saw_lu_tlsldm = 1;
+         if (++info->n_slaves > 1)
            {
-             size_t len = strlen (buffer);
-             const char *errmsg;
-
-             info = ((struct alpha_literal_tag *)
-                     xcalloc (sizeof (struct alpha_literal_tag) + len, 1));
-
-             info->segment = now_seg;
-             info->sequence = insn->sequence[i];
-             strcpy (info->string, buffer);
-             errmsg = hash_insert (alpha_literal_hash, info->string, (PTR) info);
-             if (errmsg)
-               as_bad (errmsg);
+             if (info->saw_lu_tlsgd)
+               as_bad (_("too many lituse insns for !lituse_tlsgd!%ld"),
+                       insn->sequence);
+             else if (info->saw_lu_tlsldm)
+               as_bad (_("too many lituse insns for !lituse_tlsldm!%ld"),
+                       insn->sequence);
            }
-         info->n_lituses++;
          fixP->tc_fix_data.info = info;
-         fixP->tc_fix_data.next_lituse = info->lituse;
-         info->lituse = fixP;
+         fixP->tc_fix_data.next_reloc = info->slaves;
+         info->slaves = fixP;
          if (info->segment != now_seg)
            info->multi_section_p = 1;
+         break;
+
+       case BFD_RELOC_ALPHA_TLSGD:
+         fixP->fx_no_overflow = 1;
 
+         if (insn->sequence == 0)
+           break;
+         info = get_alpha_reloc_tag (insn->sequence);
+         if (info->saw_tlsgd)
+           as_bad (_("duplicate !tlsgd!%ld"), insn->sequence);
+         else if (info->saw_tlsldm)
+           as_bad (_("sequence number in use for !tlsldm!%ld"),
+                   insn->sequence);
+         else
+           info->saw_tlsgd = 1;
+         fixP->tc_fix_data.info = info;
+         break;
+
+       case BFD_RELOC_ALPHA_TLSLDM:
+         fixP->fx_no_overflow = 1;
+
+         if (insn->sequence == 0)
+           break;
+         info = get_alpha_reloc_tag (insn->sequence);
+         if (info->saw_tlsldm)
+           as_bad (_("duplicate !tlsldm!%ld"), insn->sequence);
+         else if (info->saw_tlsgd)
+           as_bad (_("sequence number in use for !tlsgd!%ld"),
+                   insn->sequence);
+         else
+           info->saw_tlsldm = 1;
+         fixP->tc_fix_data.info = info;
          break;
-#endif
 
        default:
          if ((int) fixup->reloc < 0)
@@ -2653,14 +2794,14 @@ assemble_tokens_to_insn (opname, tok, ntok, insn)
       opcode = find_opcode_match (opcode, tok, &ntok, &cpumatch);
       if (opcode)
        {
-         assemble_insn (opcode, tok, ntok, insn);
+         assemble_insn (opcode, tok, ntok, insn, BFD_RELOC_UNUSED);
          return;
        }
       else if (cpumatch)
        as_bad (_("inappropriate arguments for opcode `%s'"), opname);
       else
        as_bad (_("opcode `%s' not supported for target %s"), opname,
-               alpha_target_name);
+               alpha_target_name);
     }
   else
     as_bad (_("unknown opcode `%s'"), opname);
@@ -2680,8 +2821,17 @@ assemble_tokens (opname, tok, ntok, local_macros_on)
   const struct alpha_opcode *opcode;
   const struct alpha_macro *macro;
   int cpumatch = 1;
+  bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
 
-  /* search macros */
+#ifdef RELOC_OP_P
+  /* If a user-specified relocation is present, this is not a macro.  */
+  if (ntok && USER_RELOC_P (tok[ntok - 1].X_op))
+    {
+      reloc = ALPHA_RELOC_TABLE (tok[ntok - 1].X_op)->reloc;
+      ntok--;
+    }
+  else
+#endif
   if (local_macros_on)
     {
       macro = ((const struct alpha_macro *)
@@ -2698,17 +2848,6 @@ assemble_tokens (opname, tok, ntok, local_macros_on)
        }
     }
 
-#ifdef RELOC_OP_P
-  if (ntok && USER_RELOC_P (tok[ntok-1].X_op))
-    {
-      const expressionS *reloc_exp = &tok[ntok-1];
-      const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op);
-      as_bad (_("Cannot use !%s!%d with %s"), r->name,
-             (int) reloc_exp->X_add_number, opname);
-      ntok--;
-    }
-#endif
-
   /* search opcodes */
   opcode = (const struct alpha_opcode *) hash_find (alpha_opcode_hash, opname);
   if (opcode)
@@ -2718,22 +2857,28 @@ assemble_tokens (opname, tok, ntok, local_macros_on)
       if (opcode)
        {
          struct alpha_insn insn;
-         assemble_insn (opcode, tok, ntok, &insn);
+         assemble_insn (opcode, tok, ntok, &insn, reloc);
+
+         /* Copy the sequence number for the reloc from the reloc token.  */
+         if (reloc != BFD_RELOC_UNUSED)
+           insn.sequence = tok[ntok].X_add_number;
+
          emit_insn (&insn);
          return;
        }
     }
 
   if (found_something)
-    if (cpumatch)
-      as_bad (_("inappropriate arguments for opcode `%s'"), opname);
-    else
-      as_bad (_("opcode `%s' not supported for target %s"), opname,
-             alpha_target_name);
+    {
+      if (cpumatch)
+       as_bad (_("inappropriate arguments for opcode `%s'"), opname);
+      else
+       as_bad (_("opcode `%s' not supported for target %s"), opname,
+               alpha_target_name);
+    }
   else
     as_bad (_("unknown opcode `%s'"), opname);
 }
-
 \f
 /* Some instruction sets indexed by lg(size) */
 static const char * const sextX_op[] = { "sextb", "sextw", "sextl", NULL };
@@ -2744,7 +2889,6 @@ static const char * const extXh_op[] = { NULL,    "extwh", "extlh", "extqh" };
 static const char * const mskXl_op[] = { "mskbl", "mskwl", "mskll", "mskql" };
 static const char * const mskXh_op[] = { NULL,    "mskwh", "msklh", "mskqh" };
 static const char * const stX_op[] = { "stb", "stw", "stl", "stq" };
-static const char * const ldX_op[] = { "ldb", "ldw", "ldll", "ldq" };
 static const char * const ldXu_op[] = { "ldbu", "ldwu", NULL, NULL };
 
 /* Implement the ldgp macro.  */
@@ -2765,17 +2909,6 @@ FIXME
   expressionS newtok[3];
   expressionS addend;
 
-#ifdef RELOC_OP_P
-  if (ntok && USER_RELOC_P (tok[ntok-1].X_op))
-    {
-      const expressionS *reloc_exp = &tok[ntok-1];
-      const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op);
-      as_bad (_("Cannot use !%s!%d with %s"), r->name,
-             (int) reloc_exp->X_add_number, "ldgp");
-      ntok--;
-    }
-#endif
-
 #ifdef OBJ_ECOFF
   if (regno (tok[2].X_add_number) == AXP_REG_PV)
     ecoff_set_gp_prolog_size (0);
@@ -2799,6 +2932,7 @@ FIXME
   insn.nfixups = 1;
   insn.fixups[0].exp = addend;
   insn.fixups[0].reloc = BFD_RELOC_ALPHA_GPDISP_HI16;
+  insn.sequence = next_sequence_num;
 
   emit_insn (&insn);
 
@@ -2813,6 +2947,7 @@ FIXME
   insn.nfixups = 1;
   insn.fixups[0].exp = addend;
   insn.fixups[0].reloc = BFD_RELOC_ALPHA_GPDISP_LO16;
+  insn.sequence = next_sequence_num--;
 
   emit_insn (&insn);
 #endif /* OBJ_ECOFF || OBJ_ELF */
@@ -2854,7 +2989,7 @@ add_to_link_pool (basesym, sym, addend)
          {
            if (range_signed_16 (offset))
              {
-               return offset;
+               return offset;
              }
          }
       }
@@ -2892,18 +3027,18 @@ add_to_link_pool (basesym, sym, addend)
    If explicit relocations of the form !literal!<number> are allowed,
    and used, then explict_reloc with be an expression pointer.
 
-   Finally, the return value is true if the calling macro may emit a
-   LITUSE reloc if otherwise appropriate.  */
+   Finally, the return value is nonzero if the calling macro may emit
+   a LITUSE reloc if otherwise appropriate; the return value is the
+   sequence number to use.  */
 
-static int
-load_expression (targreg, exp, pbasereg, poffset, explicit_reloc)
+static long
+load_expression (targreg, exp, pbasereg, poffset)
      int targreg;
      const expressionS *exp;
      int *pbasereg;
      expressionS *poffset;
-     const expressionS *explicit_reloc;
 {
-  int emit_lituse = 0;
+  long emit_lituse = 0;
   offsetT addend = exp->X_add_number;
   int basereg = *pbasereg;
   struct alpha_insn insn;
@@ -2953,9 +3088,9 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc)
 
        assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
 
-       assert (explicit_reloc == (const expressionS *) 0);
        assert (insn.nfixups == 1);
        insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL;
+       insn.sequence = emit_lituse = next_sequence_num--;
 #endif /* OBJ_ECOFF */
 #ifdef OBJ_ELF
        /* emit "ldq r, gotoff(gp)" */
@@ -2975,8 +3110,9 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc)
        /* XXX: Disable this .got minimizing optimization so that we can get
           better instruction offset knowledge in the compiler.  This happens
           very infrequently anyway.  */
-       if (1 || (!range_signed_32 (addend)
-           && (alpha_noat_on || targreg == AXP_REG_AT)))
+       if (1
+           || (!range_signed_32 (addend)
+               && (alpha_noat_on || targreg == AXP_REG_AT)))
          {
            newtok[1] = *exp;
            addend = 0;
@@ -2991,25 +3127,14 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc)
        assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
 
        assert (insn.nfixups == 1);
-       if (!explicit_reloc)
-         insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL;
-       else
-         {
-#ifdef RELOC_OP_P
-           insn.fixups[0].reloc
-             = (ALPHA_RELOC_TABLE (explicit_reloc->X_op))->reloc;
-           insn.sequence[0] = explicit_reloc->X_add_number;
-#else
-           abort ();
-#endif
-         }
+       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.  */
 
-       assert (explicit_reloc == (const expressionS *) 0);
        if (exp->X_add_symbol == alpha_evax_proc.symbol)
          {
            if (range_signed_16 (addend))
@@ -3051,8 +3176,6 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc)
        emit_insn (&insn);
 
 #ifndef OBJ_EVAX
-       emit_lituse = 1;
-
        if (basereg != alpha_gp_register && basereg != AXP_REG_ZERO)
          {
            /* emit "addq r, base, r" */
@@ -3068,14 +3191,12 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc)
       break;
 
     case O_constant:
-      assert (explicit_reloc == (const expressionS *) 0);
       break;
 
     case O_subtract:
       /* Assume that this difference expression will be resolved to an
         absolute value and that that value will fit in 16 bits.  */
 
-      assert (explicit_reloc == (const expressionS *) 0);
       set_tok_reg (newtok[0], targreg);
       newtok[1] = *exp;
       set_tok_preg (newtok[2], basereg);
@@ -3102,8 +3223,9 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc)
   if (!range_signed_32 (addend))
     {
       offsetT lit;
+      long seq_num = next_sequence_num--;
 
-      /* for 64-bit addends, just put it in the literal pool */
+      /* For 64-bit addends, just put it in the literal pool.  */
 
 #ifdef OBJ_EVAX
       /* emit "ldq targreg, lit(basereg)"  */
@@ -3163,6 +3285,7 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc)
 #ifdef OBJ_ELF
       insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL;
 #endif
+      insn.sequence = seq_num;
 
       emit_insn (&insn);
 
@@ -3174,16 +3297,10 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc)
       assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
 
       assert (insn.nfixups < MAX_INSN_FIXUPS);
-      if (insn.nfixups > 0)
-       {
-         memmove (&insn.fixups[1], &insn.fixups[0],
-                  sizeof (struct alpha_fixup) * insn.nfixups);
-       }
+      insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
+      insn.fixups[insn.nfixups].exp.X_op = O_absent;
       insn.nfixups++;
-      insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE;
-      insn.fixups[0].exp.X_op = O_symbol;
-      insn.fixups[0].exp.X_add_symbol = section_symbol (now_seg);
-      insn.fixups[0].exp.X_add_number = LITUSE_BASE;
+      insn.sequence = seq_num;
       emit_lituse = 0;
 
       emit_insn (&insn);
@@ -3263,66 +3380,19 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc)
    large constants.  */
 
 static void
-emit_lda (tok, ntok, opname)
+emit_lda (tok, ntok, unused)
      const expressionS *tok;
      int ntok;
-     const PTR opname;
+     const PTR unused ATTRIBUTE_UNUSED;
 {
   int basereg;
-  const expressionS *reloc = (const expressionS *) 0;
-
-#ifdef RELOC_OP_P
-  if (ntok && USER_RELOC_P (tok[ntok-1].X_op))
-    {
-      const struct alpha_reloc_op_tag *r;
-
-      reloc = &tok[ntok-1];
-      r = ALPHA_RELOC_TABLE (reloc->X_op);
-      switch (reloc->X_op)
-       {
-       default:
-         as_bad (_("Cannot use !%s!%d with %s"), r->name,
-                 (int) reloc->X_add_number, (const char *) opname);
-
-         reloc = (const expressionS *) 0;
-         ntok--;
-         break;
-
-       case O_literal:
-         ntok--;
-         break;
-
-         /* For lda $x,0($x)!lituse_base!y, don't use load_expression, since
-            it is really too general for our needs.  Instead just generate the
-            lda directly.  */
-       case O_lituse_base:
-         if (ntok != 4
-             || tok[0].X_op != O_register
-             || !is_ir_num (tok[0].X_add_number)
-             || tok[1].X_op != O_constant
-             || tok[2].X_op != O_pregister
-             || !is_ir_num (tok[2].X_add_number))
-           {
-             as_bad (_("bad instruction format for lda !%s!%ld"), r->name,
-                     (long) reloc->X_add_number);
-
-             reloc = (const expressionS *) 0;
-             ntok--;
-             break;
-           }
-
-         emit_loadstore (tok, ntok, "lda");
-         return;
-       }
-    }
-#endif
 
   if (ntok == 2)
     basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register);
   else
     basereg = tok[2].X_add_number;
 
-  (void) load_expression (tok[0].X_add_number, &tok[1], &basereg, NULL, reloc);
+  (void) load_expression (tok[0].X_add_number, &tok[1], &basereg, NULL);
 }
 
 /* The ldah macro differs from the ldah instruction in that it has $31
@@ -3336,17 +3406,6 @@ emit_ldah (tok, ntok, unused)
 {
   expressionS newtok[3];
 
-#ifdef RELOC_OP_P
-  if (ntok && USER_RELOC_P (tok[ntok-1].X_op))
-    {
-      const expressionS *reloc_exp = &tok[ntok-1];
-      const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op);
-      as_bad (_("Cannot use !%s!%d with %s"), r->name,
-             (int) reloc_exp->X_add_number, "ldah");
-      ntok--;
-    }
-#endif
-
   newtok[0] = tok[0];
   newtok[1] = tok[1];
   set_tok_preg (newtok[2], AXP_REG_ZERO);
@@ -3364,83 +3423,31 @@ emit_ir_load (tok, ntok, opname)
      int ntok;
      const PTR opname;
 {
-  int basereg, lituse;
+  int basereg;
+  long lituse;
   expressionS newtok[3];
   struct alpha_insn insn;
 
-#ifdef RELOC_OP_P
-  const expressionS *reloc = (const expressionS *) 0;
-
-  if (ntok && USER_RELOC_P (tok[ntok-1].X_op))
-    {
-      const struct alpha_reloc_op_tag *r;
-
-      reloc = &tok[ntok-1];
-      switch (reloc->X_op)
-       {
-       case O_lituse_base:
-         ntok--;
-         break;
-
-       case O_literal:
-         if (strcmp ((const char *) opname, "ldq") == 0)
-           {
-             emit_lda (tok, ntok, opname);
-             return;
-           }
-
-         /* fall through */
-       default:
-         ntok--;
-         r = ALPHA_RELOC_TABLE (reloc->X_op);
-         as_bad (_("Cannot use !%s!%d with %s"), r->name,
-                 (int) reloc->X_add_number, (const char *) opname);
-       }
-    }
-#endif
-
   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], (const expressionS *) 0);
+                           &newtok[1]);
 
   newtok[0] = tok[0];
   set_tok_preg (newtok[2], basereg);
 
   assemble_tokens_to_insn ((const char *) opname, newtok, 3, &insn);
 
-#ifdef RELOC_OP_P
-  if (reloc)
-    {
-      int nfixups = insn.nfixups;
-      const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc->X_op);
-
-      assert (nfixups < MAX_INSN_FIXUPS);
-      insn.fixups[nfixups].reloc = r->reloc;
-      insn.fixups[nfixups].exp.X_op = O_symbol;
-      insn.fixups[nfixups].exp.X_add_symbol = section_symbol (now_seg);
-      insn.fixups[nfixups].exp.X_add_number = r->lituse;
-      insn.sequence[nfixups] = reloc->X_add_number;
-      insn.nfixups++;
-    }
-#endif
-
   if (lituse)
     {
       assert (insn.nfixups < MAX_INSN_FIXUPS);
-      if (insn.nfixups > 0)
-       {
-         memmove (&insn.fixups[1], &insn.fixups[0],
-                  sizeof (struct alpha_fixup) * insn.nfixups);
-       }
+      insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
+      insn.fixups[insn.nfixups].exp.X_op = O_absent;
       insn.nfixups++;
-      insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE;
-      insn.fixups[0].exp.X_op = O_symbol;
-      insn.fixups[0].exp.X_add_symbol = section_symbol (now_seg);
-      insn.fixups[0].exp.X_add_number = LITUSE_BASE;
+      insn.sequence = lituse;
     }
 
   emit_insn (&insn);
@@ -3455,25 +3462,11 @@ emit_loadstore (tok, ntok, opname)
      int ntok;
      const PTR opname;
 {
-  int basereg, lituse;
+  int basereg;
+  long lituse;
   expressionS newtok[3];
   struct alpha_insn insn;
 
-#ifdef RELOC_OP_P
-  const expressionS *reloc = (const expressionS *) 0;
-
-  if (ntok && USER_RELOC_P (tok[ntok-1].X_op))
-    {
-      reloc = &tok[--ntok];
-      if (reloc->X_op != O_lituse_base)
-       {
-         const struct alpha_reloc_op_tag *r = &alpha_reloc_op[ reloc->X_md ];
-         as_bad (_("Cannot use !%s!%d with %s"), r->name,
-                 (int) reloc->X_add_number, (const char *) opname);
-       }
-    }
-#endif
-
   if (ntok == 2)
     basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register);
   else
@@ -3484,8 +3477,7 @@ emit_loadstore (tok, ntok, opname)
       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],
-                               (const expressionS *) 0);
+      lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, &newtok[1]);
     }
   else
     {
@@ -3498,35 +3490,13 @@ emit_loadstore (tok, ntok, opname)
 
   assemble_tokens_to_insn ((const char *) opname, newtok, 3, &insn);
 
-#ifdef RELOC_OP_P
-  if (reloc)
-    {
-      int nfixups = insn.nfixups;
-      const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc->X_op);
-
-      assert (nfixups < MAX_INSN_FIXUPS);
-      insn.fixups[nfixups].reloc = r->reloc;
-      insn.fixups[nfixups].exp.X_op = O_symbol;
-      insn.fixups[nfixups].exp.X_add_symbol = section_symbol (now_seg);
-      insn.fixups[nfixups].exp.X_add_number = r->lituse;
-      insn.sequence[nfixups] = reloc->X_add_number;
-      insn.nfixups++;
-    }
-#endif
-
   if (lituse)
     {
       assert (insn.nfixups < MAX_INSN_FIXUPS);
-      if (insn.nfixups > 0)
-       {
-         memmove (&insn.fixups[1], &insn.fixups[0],
-                  sizeof (struct alpha_fixup) * insn.nfixups);
-       }
+      insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
+      insn.fixups[insn.nfixups].exp.X_op = O_absent;
       insn.nfixups++;
-      insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE;
-      insn.fixups[0].exp.X_op = O_symbol;
-      insn.fixups[0].exp.X_add_symbol = section_symbol (now_seg);
-      insn.fixups[0].exp.X_add_number = LITUSE_BASE;
+      insn.sequence = lituse;
     }
 
   emit_insn (&insn);
@@ -3545,41 +3515,57 @@ emit_ldXu (tok, ntok, vlgsize)
   else
     {
       expressionS newtok[3];
-
-#ifdef RELOC_OP_P
-  if (ntok && USER_RELOC_P (tok[ntok-1].X_op))
-       {
-         const expressionS *reloc_exp = &tok[ntok-1];
-         const struct alpha_reloc_op_tag *r
-           = ALPHA_RELOC_TABLE (reloc_exp->X_op);
-
-         as_bad (_("Cannot use !%s!%d with %s"), r->name,
-                 (int) reloc_exp->X_add_number, "ldbu/ldwu");
-         ntok--;
-       }
-#endif
+      struct alpha_insn insn;
+      int basereg;
+      long lituse;
 
       if (alpha_noat_on)
        as_bad (_("macro requires $at register while noat in effect"));
 
+      if (ntok == 2)
+       basereg = (tok[1].X_op == O_constant
+                  ? AXP_REG_ZERO : alpha_gp_register);
+      else
+       basereg = tok[2].X_add_number;
+
       /* emit "lda $at, exp" */
 
-      memcpy (newtok, tok, sizeof (expressionS) * ntok);
-      newtok[0].X_add_number = AXP_REG_AT;
-      assemble_tokens ("lda", newtok, ntok, 1);
+      lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL);
 
       /* emit "ldq_u targ, 0($at)" */
 
       newtok[0] = tok[0];
       set_tok_const (newtok[1], 0);
-      set_tok_preg (newtok[2], AXP_REG_AT);
-      assemble_tokens ("ldq_u", newtok, 3, 1);
+      set_tok_preg (newtok[2], basereg);
+      assemble_tokens_to_insn ("ldq_u", newtok, 3, &insn);
+
+      if (lituse)
+       {
+         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++;
+         insn.sequence = lituse;
+       }
+
+      emit_insn (&insn);
 
       /* emit "extXl targ, $at, targ" */
 
-      set_tok_reg (newtok[1], AXP_REG_AT);
+      set_tok_reg (newtok[1], basereg);
       newtok[2] = newtok[0];
-      assemble_tokens (extXl_op[(long) vlgsize], newtok, 3, 1);
+      assemble_tokens_to_insn (extXl_op[(long) vlgsize], newtok, 3, &insn);
+
+      if (lituse)
+       {
+         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++;
+         insn.sequence = lituse;
+       }
+
+      emit_insn (&insn);
     }
 }
 
@@ -3626,7 +3612,7 @@ emit_uldXu (tok, ntok, vlgsize)
   /* emit "ldq_u $t10, size-1($at)" */
 
   set_tok_reg (newtok[0], AXP_REG_T10);
-  set_tok_const (newtok[1], (1<<lgsize)-1);
+  set_tok_const (newtok[1], (1 << lgsize) - 1);
   assemble_tokens ("ldq_u", newtok, 3, 1);
 
   /* emit "extXl $t9, $at, $t9" */
@@ -3674,17 +3660,6 @@ emit_ldil (tok, ntok, unused)
 {
   expressionS newtok[2];
 
-#ifdef RELOC_OP_P
-  if (ntok && USER_RELOC_P (tok[ntok-1].X_op))
-    {
-      const expressionS *reloc_exp = &tok[ntok-1];
-      const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op);
-      as_bad (_("Cannot use !%s!%d with %s"), r->name,
-             (int) reloc_exp->X_add_number, "ldil");
-      ntok--;
-    }
-#endif
-
   memcpy (newtok, tok, sizeof (newtok));
   newtok[1].X_add_number = sign_extend_32 (tok[1].X_add_number);
 
@@ -3706,35 +3681,75 @@ emit_stX (tok, ntok, vlgsize)
   else
     {
       expressionS newtok[3];
+      struct alpha_insn insn;
+      int basereg;
+      long lituse;
 
       if (alpha_noat_on)
        as_bad (_("macro requires $at register while noat in effect"));
 
+      if (ntok == 2)
+       basereg = (tok[1].X_op == O_constant
+                  ? AXP_REG_ZERO : alpha_gp_register);
+      else
+       basereg = tok[2].X_add_number;
+
       /* emit "lda $at, exp" */
 
-      memcpy (newtok, tok, sizeof (expressionS) * ntok);
-      newtok[0].X_add_number = AXP_REG_AT;
-      assemble_tokens ("lda", newtok, ntok, 1);
+      lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL);
 
       /* emit "ldq_u $t9, 0($at)" */
 
       set_tok_reg (newtok[0], AXP_REG_T9);
       set_tok_const (newtok[1], 0);
-      set_tok_preg (newtok[2], AXP_REG_AT);
-      assemble_tokens ("ldq_u", newtok, 3, 1);
+      set_tok_preg (newtok[2], basereg);
+      assemble_tokens_to_insn ("ldq_u", newtok, 3, &insn);
+
+      if (lituse)
+       {
+         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++;
+         insn.sequence = lituse;
+       }
+
+      emit_insn (&insn);
 
       /* emit "insXl src, $at, $t10" */
 
       newtok[0] = tok[0];
-      set_tok_reg (newtok[1], AXP_REG_AT);
+      set_tok_reg (newtok[1], basereg);
       set_tok_reg (newtok[2], AXP_REG_T10);
-      assemble_tokens (insXl_op[lgsize], newtok, 3, 1);
+      assemble_tokens_to_insn (insXl_op[lgsize], newtok, 3, &insn);
+
+      if (lituse)
+       {
+         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++;
+         insn.sequence = lituse;
+       }
+
+      emit_insn (&insn);
 
       /* emit "mskXl $t9, $at, $t9" */
 
       set_tok_reg (newtok[0], AXP_REG_T9);
       newtok[2] = newtok[0];
-      assemble_tokens (mskXl_op[lgsize], newtok, 3, 1);
+      assemble_tokens_to_insn (mskXl_op[lgsize], newtok, 3, &insn);
+
+      if (lituse)
+       {
+         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++;
+         insn.sequence = lituse;
+       }
+
+      emit_insn (&insn);
 
       /* emit "or $t9, $t10, $t9" */
 
@@ -3743,9 +3758,20 @@ emit_stX (tok, ntok, vlgsize)
 
       /* emit "stq_u $t9, 0($at) */
 
-      set_tok_const (newtok[1], 0);
+      set_tok_const(newtok[1], 0);
       set_tok_preg (newtok[2], AXP_REG_AT);
-      assemble_tokens ("stq_u", newtok, 3, 1);
+      assemble_tokens_to_insn ("stq_u", newtok, 3, &insn);
+
+      if (lituse)
+       {
+         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++;
+         insn.sequence = lituse;
+       }
+
+      emit_insn (&insn);
     }
 }
 
@@ -3776,7 +3802,7 @@ emit_ustX (tok, ntok, vlgsize)
   /* emit "ldq_u $10, size-1($at)" */
 
   set_tok_reg (newtok[0], AXP_REG_T10);
-  set_tok_const (newtok[1], (1 << lgsize)-1);
+  set_tok_const (newtok[1], (1 << lgsize) - 1);
   assemble_tokens ("ldq_u", newtok, 3, 1);
 
   /* emit "insXl src, $at, $t11" */
@@ -3827,7 +3853,7 @@ emit_ustX (tok, ntok, vlgsize)
   /* emit "stq_u $t10, size-1($at)" */
 
   set_tok_reg (newtok[0], AXP_REG_T10);
-  set_tok_const (newtok[1], (1 << lgsize)-1);
+  set_tok_const (newtok[1], (1 << lgsize) - 1);
   assemble_tokens ("stq_u", newtok, 3, 1);
 }
 
@@ -3849,19 +3875,6 @@ emit_sextX (tok, ntok, vlgsize)
       int bitshift = 64 - 8 * (1 << lgsize);
       expressionS newtok[3];
 
-#ifdef RELOC_OP_P
-  if (ntok && USER_RELOC_P (tok[ntok-1].X_op))
-       {
-         const expressionS *reloc_exp = &tok[ntok-1];
-         const struct alpha_reloc_op_tag *r
-           = ALPHA_RELOC_TABLE (reloc_exp->X_op);
-
-         as_bad (_("Cannot use !%s!%d with %s"), r->name,
-                 (int) reloc_exp->X_add_number, "setxt");
-         ntok--;
-       }
-#endif
-
       /* emit "sll src,bits,dst" */
 
       newtok[0] = tok[0];
@@ -3908,17 +3921,6 @@ emit_division (tok, ntok, symname)
   symbolS *sym;
   expressionS newtok[3];
 
-#ifdef RELOC_OP_P
-  if (ntok && USER_RELOC_P (tok[ntok-1].X_op))
-    {
-      const expressionS *reloc_exp = &tok[ntok-1];
-      const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op);
-      as_bad (_("Cannot use !%s!%d with %s"), r->name,
-             (int) reloc_exp->X_add_number, (char char *) symname);
-      ntok--;
-    }
-#endif
-
   xr = regno (tok[0].X_add_number);
   yr = regno (tok[1].X_add_number);
 
@@ -3960,7 +3962,7 @@ emit_division (tok, ntok, symname)
        {
          set_tok_reg (newtok[0], xr);
          set_tok_reg (newtok[1], AXP_REG_R16);
-          assemble_tokens ("mov", newtok, 2, 1);
+         assemble_tokens ("mov", newtok, 2, 1);
        }
 
       if (yr != AXP_REG_R16 && yr != AXP_REG_R17)
@@ -4018,17 +4020,6 @@ emit_division (tok, ntok, symname)
   symbolS *sym;
   expressionS newtok[3];
 
-#ifdef RELOC_OP_P
-  if (ntok && USER_RELOC_P (tok[ntok-1].X_op))
-    {
-      const expressionS *reloc_exp = &tok[ntok-1];
-      const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op);
-      as_bad (_("Cannot use !%s!%d with %s"), r->name,
-             (int) reloc_exp->X_add_number, (const char *) symname);
-      ntok--;
-    }
-#endif
-
   xr = regno (tok[0].X_add_number);
   yr = regno (tok[1].X_add_number);
 
@@ -4072,7 +4063,7 @@ emit_division (tok, ntok, symname)
        {
          set_tok_reg (newtok[0], xr);
          set_tok_reg (newtok[1], AXP_REG_T10);
-          assemble_tokens ("mov", newtok, 2, 1);
+         assemble_tokens ("mov", newtok, 2, 1);
        }
 
       if (yr != AXP_REG_T10 && yr != AXP_REG_T11)
@@ -4123,18 +4114,8 @@ emit_jsrjmp (tok, ntok, vopname)
   const char *opname = (const char *) vopname;
   struct alpha_insn insn;
   expressionS newtok[3];
-  int r, tokidx = 0, lituse = 0;
-
-#ifdef RELOC_OP_P
-  if (ntok && USER_RELOC_P (tok[ntok-1].X_op))
-    {
-      const expressionS *reloc_exp = &tok[ntok-1];
-      const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op);
-      as_bad (_("Cannot use !%s!%d with %s"), r->name,
-             (int) reloc_exp->X_add_number, opname);
-      ntok--;
-    }
-#endif
+  int r, tokidx = 0;
+  long lituse = 0;
 
   if (tokidx < ntok && tok[tokidx].X_op == O_register)
     r = regno (tok[tokidx++].X_add_number);
@@ -4152,8 +4133,7 @@ emit_jsrjmp (tok, ntok, vopname)
   else
     {
       int basereg = alpha_gp_register;
-      lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], &basereg, NULL,
-                               (const expressionS *) 0);
+      lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], &basereg, NULL);
     }
 #endif
 
@@ -4170,20 +4150,13 @@ emit_jsrjmp (tok, ntok, vopname)
 
   assemble_tokens_to_insn (opname, newtok, 3, &insn);
 
-  /* add the LITUSE fixup */
   if (lituse)
     {
       assert (insn.nfixups < MAX_INSN_FIXUPS);
-      if (insn.nfixups > 0)
-       {
-         memmove (&insn.fixups[1], &insn.fixups[0],
-                  sizeof (struct alpha_fixup) * insn.nfixups);
-       }
+      insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_JSR;
+      insn.fixups[insn.nfixups].exp.X_op = O_absent;
       insn.nfixups++;
-      insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE;
-      insn.fixups[0].exp.X_op = O_symbol;
-      insn.fixups[0].exp.X_add_symbol = section_symbol (now_seg);
-      insn.fixups[0].exp.X_add_number = LITUSE_JSR;
+      insn.sequence = lituse;
     }
 
   emit_insn (&insn);
@@ -4202,17 +4175,6 @@ emit_retjcr (tok, ntok, vopname)
   expressionS newtok[3];
   int r, tokidx = 0;
 
-#ifdef RELOC_OP_P
-  if (ntok && USER_RELOC_P (tok[ntok-1].X_op))
-    {
-      const expressionS *reloc_exp = &tok[ntok-1];
-      const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op);
-      as_bad (_("Cannot use !%s!%d with %s"), r->name,
-             (int) reloc_exp->X_add_number, opname);
-      ntok--;
-    }
-#endif
-
   if (tokidx < ntok && tok[tokidx].X_op == O_register)
     r = regno (tok[tokidx++].X_add_number);
   else
@@ -4246,7 +4208,11 @@ s_alpha_text (i)
      int i;
 
 {
+#ifdef OBJ_ELF
+  obj_elf_text (i);
+#else
   s_text (i);
+#endif
   alpha_insn_label = NULL;
   alpha_auto_align_on = 1;
   alpha_current_align = 0;
@@ -4259,7 +4225,11 @@ static void
 s_alpha_data (i)
      int i;
 {
+#ifdef OBJ_ELF
+  obj_elf_data (i);
+#else
   s_data (i);
+#endif
   alpha_insn_label = NULL;
   alpha_auto_align_on = 1;
   alpha_current_align = 0;
@@ -4475,7 +4445,7 @@ s_alpha_ent (dummy)
              input_line_pointer++;
              SKIP_WHITESPACE ();
            }
-         if (isdigit (*input_line_pointer) || *input_line_pointer == '-')
+         if (ISDIGIT (*input_line_pointer) || *input_line_pointer == '-')
            (void) get_absolute_expression ();
        }
       demand_empty_rest_of_line ();
@@ -4514,7 +4484,7 @@ s_alpha_end (dummy)
                (expressionS *) xmalloc (sizeof (expressionS));
              symbol_get_obj (sym)->size->X_op = O_subtract;
              symbol_get_obj (sym)->size->X_add_symbol
-               = symbol_new ("L0\001", now_seg, frag_now_fix (), frag_now);
+               = symbol_new ("L0\001", now_seg, frag_now_fix (), frag_now);
              symbol_get_obj (sym)->size->X_op_symbol = sym;
              symbol_get_obj (sym)->size->X_add_number = 0;
            }
@@ -4534,9 +4504,9 @@ s_alpha_mask (fp)
   if (ECOFF_DEBUGGING)
     {
       if (fp)
-        ecoff_directive_fmask (0);
+       ecoff_directive_fmask (0);
       else
-        ecoff_directive_mask (0);
+       ecoff_directive_mask (0);
     }
   else
     discard_rest_of_line ();
@@ -4570,24 +4540,24 @@ s_alpha_prologue (ignore)
 
   switch (arg)
     {
-      case 0: /* No PV required.  */
-       S_SET_OTHER (sym, STO_ALPHA_NOPV
-                         | (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD));
-       break;
-      case 1: /* Std GP load.  */
-       S_SET_OTHER (sym, STO_ALPHA_STD_GPLOAD
-                         | (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD));
-       break;
-      case 2: /* Non-std use of PV.  */
-       break;
-
-      default:
-       as_bad (_("Invalid argument %d to .prologue."), arg);
-       break;
+    case 0: /* No PV required.  */
+      S_SET_OTHER (sym, STO_ALPHA_NOPV
+                  | (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD));
+      break;
+    case 1: /* Std GP load.  */
+      S_SET_OTHER (sym, STO_ALPHA_STD_GPLOAD
+                  | (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD));
+      break;
+    case 2: /* Non-std use of PV.  */
+      break;
+
+    default:
+      as_bad (_("Invalid argument %d to .prologue."), arg);
+      break;
     }
 }
 
-static char * first_file_directive;
+static char *first_file_directive;
 
 static void
 s_alpha_file (ignore)
@@ -4634,7 +4604,7 @@ s_alpha_stab (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_flags (stdoutput, sec, SEC_HAS_CONTENTS | SEC_READONLY);
       bfd_set_section_alignment (stdoutput, sec, 3);
 
       ecoff_read_begin_hook ();
@@ -4642,7 +4612,7 @@ s_alpha_stab (n)
       if (first_file_directive)
        {
          char *save_ilp = input_line_pointer;
-          input_line_pointer = first_file_directive;
+         input_line_pointer = first_file_directive;
          ecoff_directive_file (0);
          input_line_pointer = save_ilp;
          free (first_file_directive);
@@ -4690,7 +4660,7 @@ s_alpha_section (secid)
 {
   int temp;
 #define EVAX_SECTION_COUNT 5
-  static char *section_name[EVAX_SECTION_COUNT+1] =
+  static char *section_name[EVAX_SECTION_COUNT + 1] =
     { "NULL", ".rdata", ".comm", ".link", ".ctors", ".dtors" };
 
   if ((secid <= 0) || (secid > EVAX_SECTION_COUNT))
@@ -4869,34 +4839,33 @@ s_alpha_pdesc (ignore)
   seginfo->literal_pool_size += 16;
 
   *p = alpha_evax_proc.pdsckind
-       | ((alpha_evax_proc.framereg == 29) ? PDSC_S_M_BASE_REG_IS_FP : 0);
-  *(p+1) = PDSC_S_M_NATIVE
-          | PDSC_S_M_NO_JACKET;
+    | ((alpha_evax_proc.framereg == 29) ? PDSC_S_M_BASE_REG_IS_FP : 0);
+  *(p + 1) = PDSC_S_M_NATIVE | PDSC_S_M_NO_JACKET;
 
   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;
-       break;
-      case PDSC_S_K_KIND_FP_STACK:
-       md_number_to_chars (p+2, (valueT) alpha_evax_proc.rsa_offset, 2);
-       break;
-      default:         /* impossible */
-       break;
+    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;
+      break;
+    case PDSC_S_K_KIND_FP_STACK:
+      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 + 4) = 0;
+  *(p + 5) = alpha_evax_proc.type & 0x0f;
 
   /* Signature offset.  */
-  md_number_to_chars (p+6, (valueT) 0, 2);
+  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)
     return;
@@ -4910,10 +4879,10 @@ s_alpha_pdesc (ignore)
   /* pdesc+16: Size.  */
   md_number_to_chars (p, (valueT) alpha_evax_proc.framesize, 4);
 
-  md_number_to_chars (p+4, (valueT) 0, 2);
+  md_number_to_chars (p + 4, (valueT) 0, 2);
 
   /* Entry length.  */
-  md_number_to_chars (p+6, alpha_evax_proc.prologue, 2);
+  md_number_to_chars (p + 6, alpha_evax_proc.prologue, 2);
 
   if (alpha_evax_proc.pdsckind == PDSC_S_K_KIND_FP_REGISTER)
     return;
@@ -4927,7 +4896,7 @@ s_alpha_pdesc (ignore)
   /* 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 + 4, alpha_evax_proc.fmask, 4);
 
   return;
 }
@@ -4967,7 +4936,7 @@ s_alpha_name (ignore)
   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);
+  fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &exp, 0, BFD_RELOC_64);
 
   return;
 }
@@ -5169,7 +5138,7 @@ s_alpha_gprel32 (ignore)
 
   p = frag_more (4);
   memset (p, 0, 4);
-  fix_new_exp (frag_now, p-frag_now->fr_literal, 4,
+  fix_new_exp (frag_now, p - frag_now->fr_literal, 4,
               &e, 0, BFD_RELOC_GPREL32);
 }
 
@@ -5440,7 +5409,7 @@ s_alpha_arch (ignored)
   for (p = cpu_types; p->name; ++p)
     if (strcmp (name, p->name) == 0)
       {
-        alpha_target_name = p->name, alpha_target = p->flags;
+       alpha_target_name = p->name, alpha_target = p->flags;
        goto found;
       }
   as_warn ("Unknown CPU identifier `%s'", name);
@@ -5449,34 +5418,32 @@ found:
   *input_line_pointer = ch;
   demand_empty_rest_of_line ();
 }
-
 \f
-
 #ifdef DEBUG1
 /* print token expression with alpha specific extension.  */
 
 static void
 alpha_print_token (f, exp)
-    FILE *f;
-    const expressionS *exp;
+     FILE *f;
+     const expressionS *exp;
 {
   switch (exp->X_op)
     {
-      case O_cpregister:
-       putc (',', f);
-       /* FALLTHRU */
-      case O_pregister:
-       putc ('(', f);
-       {
-         expressionS nexp = *exp;
-         nexp.X_op = O_register;
-         print_expr (f, &nexp);
-       }
-       putc (')', f);
-       break;
-      default:
-       print_expr (f, exp);
-       break;
+    case O_cpregister:
+      putc (',', f);
+      /* FALLTHRU */
+    case O_pregister:
+      putc ('(', f);
+      {
+       expressionS nexp = *exp;
+       nexp.X_op = O_register;
+       print_expr (f, &nexp);
+      }
+      putc (')', f);
+      break;
+    default:
+      print_expr (f, exp);
+      break;
     }
   return;
 }
@@ -5484,8 +5451,7 @@ alpha_print_token (f, exp)
 \f
 /* The target specific pseudo-ops which we support.  */
 
-const pseudo_typeS md_pseudo_table[] =
-{
+const pseudo_typeS md_pseudo_table[] = {
 #ifdef OBJ_ECOFF
   {"comm", s_alpha_comm, 0},   /* osf1 compiler does this */
   {"rdata", s_alpha_rdata, 0},
@@ -5592,7 +5558,6 @@ const pseudo_typeS md_pseudo_table[] =
 
   {NULL, 0, 0},
 };
-
 \f
 /* Build a BFD section with its flags set appropriately for the .lita,
    .lit8, or .lit4 sections.  */
@@ -5640,7 +5605,8 @@ select_gp_value ()
   assert (alpha_gp_value == 0);
 
   /* Get minus-one in whatever width...  */
-  alpha_gp_value = 0; alpha_gp_value--;
+  alpha_gp_value = 0;
+  alpha_gp_value--;
 
   /* Select the smallest VMA of these existing sections.  */
   maybe_set_gp (alpha_lita_section);
@@ -5664,6 +5630,34 @@ select_gp_value ()
 }
 #endif /* OBJ_ECOFF */
 
+#ifdef OBJ_ELF
+/* Map 's' to SHF_ALPHA_GPREL.  */
+
+int
+alpha_elf_section_letter (letter, ptr_msg)
+     int letter;
+     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");
+  return 0;
+}
+
+/* Map SHF_ALPHA_GPREL to SEC_SMALL_DATA.  */
+
+flagword
+alpha_elf_section_flags (flags, attr, type)
+     flagword flags;
+     int attr, type ATTRIBUTE_UNUSED;
+{
+  if (attr & SHF_ALPHA_GPREL)
+    flags |= SEC_SMALL_DATA;
+  return flags;
+}
+#endif /* OBJ_ELF */
+
 /* Called internally to handle all alignment needs.  This takes care
    of eliding calls to frag_align if'n the cached current alignment
    says we've already got it, as well as taking care of the auto-align
@@ -5710,10 +5704,10 @@ void
 alpha_handle_align (fragp)
      fragS *fragp;
 {
-  static char const unop[4] = { 0x00, 0x00, 0xe0, 0x2f };
+  static char const unop[4] = { 0x00, 0x00, 0xfe, 0x2f };
   static char const nopunop[8] = {
-       0x1f, 0x04, 0xff, 0x47,
-       0x00, 0x00, 0xe0, 0x2f
+    0x1f, 0x04, 0xff, 0x47,
+    0x00, 0x00, 0xfe, 0x2f
   };
 
   int bytes, fix;
This page took 0.067818 seconds and 4 git commands to generate.