This is the mail archive of the binutils@sourceware.cygnus.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

alpha patch 1 of 2


I'm adding explicit relocation support for the Alpha for a contract
(where you use !literal!<sequence> for pointer loads, and
!lituse_base!<sequence> for each memory reference that uses the
address, which gets turned into LITERAL and LITUSE relocations, which
in turn can be optimized by the linker if -relax is used), and checked
in the following patch against GAS to add support for !literal and
!lituse_base.

1999-11-22  Michael Meissner  <meissner@cygnus.com>

	* config/tc-alpha.c (toplevel): Include struc-symbol.h.
	(alpha_macro_arg): Add MACRO_{LITERAL,BASE,BYTOFF,JSR} cases.
	(O_...): Add new machine dependent expressions if we are handling
	explicit relocations.
	(alpha_reloc_op): New static table holding the explicit relocation
	information.
	(alpha_literal_hash): New static to hold the hash table for
	explicit relocations.
	(alpha_macros): Add support for explicit relocations.
	(md_begin): If explicit relocations, initialize hash table.
	(md_assemble): Don't print a second error if tokenize_arguments
	already printed an error message.
	(md_apply_fix): Add support for explicit relocations.
	(alpha_force_relocation): Ditto.
	(alpha_fix_adjustable): Ditto.
	(alpha_adjust_symtab): New function to support explicit
	relocations.
	(alpha_adjust_symtab_relocs): Ditto.
	(debug_exp): Debug stub compiled if DEBUG_ALPHA is defined.
	(tokenize_arguments): Add debug code if DEBUG_ALPHA is defined.
	Add support for explicit relocations.  Return -2 if an error
	message was already printed.
	(find_macro_match): Add support for explicit relocations.  Comment
	each of the cases.
	(emit_insn): Add support for explicit relocations.
	(assemble_tokens): Ditto.
	(emit_ldgp): Ditto.
	(load_expression): Ditto.
	(emit_lda): Ditto.
	(emit_ldah): Ditto.
	(emit_ir_load): Ditto.
	(emit_loadstore): Ditto.
	(emit_ldXu): Ditto.
	(emit_ldil): Ditto.
	(emit_sextX): Ditto.
	(emit_division): Ditto.
	(emit_jsrjmp): Ditto.
	(emit_retjcr): Ditto.

	* config/tc-alpha.h (RELOC_OP_P): Enable explicit relocations if
	ELF object format.
	(tc_adjust_symtab): If explicit relocations, call the function
	alpha_adjust_symtab.
	(TC_FIX_TYPE): Add fields to be able to move explicit lituse
	relocations next to the literal relocation they reference.
	(TC_INIT_FIX_DATA): Initialize the new fields.
	(TC_FIX_DATA_PRINT): Print the new fields if DEBUG5 is defined.

*** gas/config/tc-alpha.c.~1~	Mon Nov 22 13:32:33 1999
--- gas/config/tc-alpha.c	Mon Nov 22 09:35:14 1999
***************
*** 51,56 ****
--- 51,57 ----
  
  #include "as.h"
  #include "subsegs.h"
+ #include "struc-symbol.h"
  #include "ecoff.h"
  
  #include "opcode/alpha.h"
***************
*** 64,69 ****
--- 65,73 ----
  
  /* Local types */
  
+ #define TOKENIZE_ERROR -1
+ #define TOKENIZE_ERROR_REPORT -2
+ 
  #define MAX_INSN_FIXUPS 2
  #define MAX_INSN_ARGS 5
  
*************** struct alpha_insn
*** 78,88 ****
    unsigned insn;
    int nfixups;
    struct alpha_fixup fixups[MAX_INSN_FIXUPS];
  };
  
  enum alpha_macro_arg
  {
!   MACRO_EOA = 1, MACRO_IR, MACRO_PIR, MACRO_CPIR, MACRO_FPR, MACRO_EXP
  };
  
  struct alpha_macro
--- 82,103 ----
    unsigned insn;
    int nfixups;
    struct alpha_fixup fixups[MAX_INSN_FIXUPS];
+   unsigned sequence[MAX_INSN_FIXUPS];
  };
  
  enum alpha_macro_arg
  {
!   MACRO_EOA = 1,
!   MACRO_IR,
!   MACRO_PIR,
!   MACRO_OPIR,
!   MACRO_CPIR,
!   MACRO_FPR,
!   MACRO_EXP,
!   MACRO_LITERAL,
!   MACRO_BASE,
!   MACRO_BYTOFF,
!   MACRO_JSR
  };
  
  struct alpha_macro
*************** struct alpha_macro
*** 98,103 ****
--- 113,133 ----
  #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.  */
+ #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
+ 
+ 
  /* Macros for extracting the type and number of encoded register tokens */
  
  #define is_ir_num(x)		(((x) & 32) == 0)
*************** static void assemble_tokens
*** 180,186 ****
    PARAMS ((const char *, const expressionS *, int, int));
  
  static int load_expression
!   PARAMS ((int, const expressionS *, int *, expressionS *));
  
  static void emit_ldgp PARAMS ((const expressionS *, int, const PTR));
  static void emit_division PARAMS ((const expressionS *, int, const PTR));
--- 210,217 ----
    PARAMS ((const char *, const expressionS *, int, int));
  
  static int load_expression
!   PARAMS ((int, const expressionS *, int *, expressionS *,
! 	   const expressionS *));
  
  static void emit_ldgp PARAMS ((const expressionS *, int, const PTR));
  static void emit_division PARAMS ((const expressionS *, int, const PTR));
*************** static void select_gp_value PARAMS ((voi
*** 235,240 ****
--- 266,275 ----
  #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
+ 
  
  /* Generic assembler global variables which must be defined by all
     targets.  */
*************** static int alpha_flag_show_after_trunc =
*** 432,437 ****
--- 467,576 ----
  
  #endif
  
+ #ifdef RELOC_OP_P
+ /* A table to map the spelling of a relocation operand into an appropriate
+    bfd_reloc_code_real_type type.  The table is assumed to be ordered such
+    that op-O_literal indexes into it.  */
+ 
+ #define ALPHA_RELOC_TABLE(op)						\
+ &alpha_reloc_op[ ((!USER_RELOC_P (op))					\
+ 		  ? (abort (), 0)					\
+ 		  : (int)(op) - (int)O_literal) ]
+ 
+ #define LITUSE_BASE	1
+ #define LITUSE_BYTOFF	2
+ #define LITUSE_JSR	3
+ 
+ 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 */
+ } 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 */
+   },
+ };
+ 
+ static const int alpha_num_reloc_op
+   = sizeof(alpha_reloc_op) / sizeof(*alpha_reloc_op);
+ 
+ /* 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
+ {
+   fixS *lituse;			/* head of linked list of !literals */
+   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 */
+   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
+ 
  /* A table of CPU names and opcode sets.  */
  
  static const struct cpu_type
*************** static const struct cpu_type
*** 473,539 ****
  static const struct alpha_macro alpha_macros[] = {
  /* Load/Store macros */
    { "lda",	emit_lda, NULL,
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "ldah",	emit_ldah, NULL,
      { MACRO_IR, MACRO_EXP, MACRO_EOA } },
  
    { "ldl",	emit_ir_load, "ldl",
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "ldl_l",	emit_ir_load, "ldl_l",
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "ldq",	emit_ir_load, "ldq",
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "ldq_l",	emit_ir_load, "ldq_l",
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "ldq_u",	emit_ir_load, "ldq_u",
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "ldf",	emit_loadstore, "ldf",
!     { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_FPR, MACRO_EXP, MACRO_EOA } },
    { "ldg",	emit_loadstore, "ldg",
!     { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_FPR, MACRO_EXP, MACRO_EOA } },
    { "lds",	emit_loadstore, "lds",
!     { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_FPR, MACRO_EXP, MACRO_EOA } },
    { "ldt",	emit_loadstore, "ldt",
!     { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_FPR, MACRO_EXP, MACRO_EOA } },
  
    { "ldb",	emit_ldX, (PTR)0,
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "ldbu",	emit_ldXu, (PTR)0,
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "ldw",	emit_ldX, (PTR)1,
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "ldwu",	emit_ldXu, (PTR)1,
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
  
    { "uldw",	emit_uldX, (PTR)1,
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "uldwu",	emit_uldXu, (PTR)1,
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "uldl",	emit_uldX, (PTR)2,
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "uldlu",	emit_uldXu, (PTR)2,
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "uldq",	emit_uldXu, (PTR)3,
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
  
    { "ldgp",	emit_ldgp, NULL,
      { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA } },
--- 612,659 ----
  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 } },
    { "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 } },
    { "ldl_l",	emit_ir_load, "ldl_l",
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "ldq",	emit_ir_load, "ldq",
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_LITERAL, MACRO_EOA } },
    { "ldq_l",	emit_ir_load, "ldq_l",
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "ldq_u",	emit_ir_load, "ldq_u",
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "ldf",	emit_loadstore, "ldf",
!     { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "ldg",	emit_loadstore, "ldg",
!     { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "lds",	emit_loadstore, "lds",
!     { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "ldt",	emit_loadstore, "ldt",
!     { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
  
    { "ldb",	emit_ldX, (PTR)0,
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "ldbu",	emit_ldXu, (PTR)0,
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "ldw",	emit_ldX, (PTR)1,
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "ldwu",	emit_ldXu, (PTR)1,
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
  
    { "uldw",	emit_uldX, (PTR)1,
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "uldwu",	emit_uldXu, (PTR)1,
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "uldl",	emit_uldX, (PTR)2,
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "uldlu",	emit_uldXu, (PTR)2,
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "uldq",	emit_uldXu, (PTR)3,
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
  
    { "ldgp",	emit_ldgp, NULL,
      { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA } },
*************** static const struct alpha_macro alpha_ma
*** 558,605 ****
  #endif
  
    { "stl",	emit_loadstore, "stl",
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "stl_c",	emit_loadstore, "stl_c",
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "stq",	emit_loadstore, "stq",
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "stq_c",	emit_loadstore, "stq_c",
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "stq_u",	emit_loadstore, "stq_u",
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "stf",	emit_loadstore, "stf",
!     { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_FPR, MACRO_EXP, MACRO_EOA } },
    { "stg",	emit_loadstore, "stg",
!     { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_FPR, MACRO_EXP, MACRO_EOA } },
    { "sts",	emit_loadstore, "sts",
!     { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_FPR, MACRO_EXP, MACRO_EOA } },
    { "stt",	emit_loadstore, "stt",
!     { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_FPR, MACRO_EXP, MACRO_EOA } },
  
    { "stb",	emit_stX, (PTR)0,
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "stw",	emit_stX, (PTR)1,
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "ustw",	emit_ustX, (PTR)1,
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "ustl",	emit_ustX, (PTR)2,
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
    { "ustq",	emit_ustX, (PTR)3,
!     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
!       MACRO_IR, MACRO_EXP, MACRO_EOA } },
  
  /* Arithmetic macros */
  #if 0
--- 678,711 ----
  #endif
  
    { "stl",	emit_loadstore, "stl",
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "stl_c",	emit_loadstore, "stl_c",
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "stq",	emit_loadstore, "stq",
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "stq_c",	emit_loadstore, "stq_c",
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "stq_u",	emit_loadstore, "stq_u",
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "stf",	emit_loadstore, "stf",
!     { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "stg",	emit_loadstore, "stg",
!     { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "sts",	emit_loadstore, "sts",
!     { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "stt",	emit_loadstore, "stt",
!     { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
  
    { "stb",	emit_stX, (PTR)0,
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "stw",	emit_stX, (PTR)1,
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "ustw",	emit_ustX, (PTR)1,
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "ustl",	emit_ustX, (PTR)2,
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
    { "ustq",	emit_ustX, (PTR)3,
!     { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } },
  
  /* Arithmetic macros */
  #if 0
*************** static const struct alpha_macro alpha_ma
*** 662,676 ****
        MACRO_IR, MACRO_EXP, MACRO_EOA */ } },
  
    { "jsr",	emit_jsrjmp, "jsr",
!     { 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_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,
--- 768,782 ----
        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 } },
    { "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 } },
    { "ret",	emit_retjcr, "ret",
      { MACRO_IR, MACRO_EXP, MACRO_EOA,
        MACRO_IR, MACRO_EOA,
*************** md_begin ()
*** 812,817 ****
--- 918,928 ----
  #endif /* OBJ_ELF */
  
    subseg_set(text_section, 0);
+ 
+ #ifdef RELOC_OP_P
+   /* Create literal lookup hash table.  */
+   alpha_literal_hash = hash_new();
+ #endif
  }
  
  /* The public interface to the instruction assembler.  */
*************** md_assemble (str)
*** 836,842 ****
    /* tokenize the rest of the line */
    if ((ntok = tokenize_arguments (str + opnamelen, tok, MAX_INSN_ARGS)) < 0)
      {
!       as_bad (_("syntax error"));
        return;
      }
  
--- 947,955 ----
    /* tokenize the rest of the line */
    if ((ntok = tokenize_arguments (str + opnamelen, tok, MAX_INSN_ARGS)) < 0)
      {
!       if (ntok != TOKENIZE_ERROR_REPORT)
! 	as_bad (_("syntax error"));
! 
        return;
      }
  
*************** md_apply_fix (fixP, valueP)
*** 1164,1169 ****
--- 1277,1295 ----
        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
+ 
      default:
        {
  	const struct alpha_operand *operand;
*************** alpha_force_relocation (f)
*** 1324,1329 ****
--- 1450,1464 ----
      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
        return 1;
  
      case BFD_RELOC_23_PCREL_S2:
*************** alpha_fix_adjustable (f)
*** 1365,1370 ****
--- 1500,1508 ----
  #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_LINKAGE:
      case BFD_RELOC_ALPHA_CODEADDR:
*************** alpha_fix_adjustable (f)
*** 1372,1377 ****
--- 1510,1523 ----
        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
        return 0;
  
      case BFD_RELOC_GPREL32:
*************** alpha_frob_file_before_adjust ()
*** 1499,1504 ****
--- 1645,1894 ----
  
  #endif /* OBJ_ECOFF */
  
+ #ifdef RELOC_OP_P
+ 
+ /* 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.
+    */
+ 
+ void
+ alpha_adjust_symtab ()
+ {
+   if (alpha_literal_hash)
+     {
+ #ifdef DEBUG2_ALPHA
+       fprintf (stderr, "alpha_adjust_symtab called\n");
+ #endif
+ 
+       /* 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);
+     }
+ }
+ 
+ 
+ /* Inner function to move LITUSE's next to the LITERAL.  */
+ 
+ static void
+ alpha_adjust_symtab_relocs (abfd, sec, ptr)
+      bfd *abfd;
+      asection *sec;
+      PTR ptr;
+ {
+   segment_info_type *seginfo = seg_info (sec);
+   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
+ 
+   /* 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;
+ 
+   /* If there are no relocations, skip the section.  */
+   if (! seginfo->fix_root)
+     return;
+ 
+   /* First rebuild the fixup chain without the expicit lituse's.  */
+   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
+ 	  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)
+ 	    as_bad_where (fixp->fx_file, fixp->fx_line,
+ 			  _("No !literal!%d 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;
+ 	}
+     }
+ 
+   /* 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)
+     {
+       for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
+ 	{
+ 	  switch (fixp->fx_r_type)
+ 	    {
+ 	    default:
+ 	      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)
+ 		{
+ 		  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;
+ 		    }
+ 		}
+ 	      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;
+ 	    }
+ 	}
+     }
+ 
+ #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 */
+ 
+ 
+ #ifdef DEBUG_ALPHA
+ static void
+ debug_exp (tok, ntok)
+      expressionS tok[];
+      int ntok;
+ {
+   int i;
+ 
+   fprintf (stderr, "debug_exp: %d tokens", ntok);
+   for (i = 0; i < ntok; i++)
+     {
+       expressionS *t = &tok[i];
+       const char *name;
+       switch (t->X_op)
+ 	{
+ 	default:			name = "unknown";		break;
+ 	case O_illegal:			name = "O_illegal";		break;
+ 	case O_absent:			name = "O_absent";		break;
+ 	case O_constant:		name = "O_constant";		break;
+ 	case O_symbol:			name = "O_symbol";		break;
+ 	case O_symbol_rva:		name = "O_symbol_rva";		break;
+ 	case O_register:		name = "O_register";		break;
+ 	case O_big:			name = "O_big";			break;
+ 	case O_uminus:			name = "O_uminus";		break;
+ 	case O_bit_not:			name = "O_bit_not";		break;
+ 	case O_logical_not:		name = "O_logical_not";		break;
+ 	case O_multiply:		name = "O_multiply";		break;
+ 	case O_divide:			name = "O_divide";		break;
+ 	case O_modulus:			name = "O_modulus";		break;
+ 	case O_left_shift:		name = "O_left_shift";		break;
+ 	case O_right_shift:		name = "O_right_shift";		break;
+ 	case O_bit_inclusive_or:	name = "O_bit_inclusive_or";	break;
+ 	case O_bit_or_not:		name = "O_bit_or_not";		break;
+ 	case O_bit_exclusive_or:	name = "O_bit_exclusive_or";	break;
+ 	case O_bit_and:			name = "O_bit_and";		break;
+ 	case O_add:			name = "O_add";			break;
+ 	case O_subtract:		name = "O_subtract";		break;
+ 	case O_eq:			name = "O_eq";			break;
+ 	case O_ne:			name = "O_ne";			break;
+ 	case O_lt:			name = "O_lt";			break;
+ 	case O_le:			name = "O_le";			break;
+ 	case O_ge:			name = "O_ge";			break;
+ 	case O_gt:			name = "O_gt";			break;
+ 	case O_logical_and:		name = "O_logical_and";		break;
+ 	case O_logical_or:		name = "O_logical_or";		break;
+ 	case O_index:			name = "O_index";		break;
+ 	case O_pregister:		name = "O_pregister";		break;
+ 	case O_cpregister:		name = "O_cpregister";		break;
+ 	case O_literal:			name = "O_literal";		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_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;
+ 	}
+ 
+       fprintf (stderr, ", %s(%s, %s, %d)", name,
+ 	       (t->X_add_symbol) ? S_GET_NAME (t->X_add_symbol) : "--",
+ 	       (t->X_op_symbol) ? S_GET_NAME (t->X_op_symbol) : "--",
+ 	       (int)t->X_add_number);
+     }
+   fprintf (stderr, "\n");
+   fflush (stderr);
+ }
+ #endif
+ 
  /* Parse the arguments to an opcode.  */
  
  static int
*************** tokenize_arguments (str, tok, ntok)
*** 1510,1515 ****
--- 1900,1915 ----
    expressionS *end_tok = tok + ntok;
    char *old_input_line_pointer;
    int saw_comma = 0, saw_arg = 0;
+ #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);
  
*************** tokenize_arguments (str, tok, ntok)
*** 1525,1530 ****
--- 1925,1996 ----
  	case '\0':
  	  goto fini;
  
+ #ifdef RELOC_OP_P
+ 	case '!':
+ 	  /* A relocation operand can be placed after the normal operand on an
+ 	     assembly language statement, and has the following form:
+ 		!relocation_type!sequence_number.  */
+ 	  if (reloc_found_p)
+ 	    {			/* only support one relocation op per insn */
+ 	      as_bad (_("More than one relocation op per insn"));
+ 	      goto err_report;
+ 	    }
+ 
+ 	  if (!saw_arg)
+ 	    goto err;
+ 
+ 	  for (p = ++input_line_pointer;
+ 	       ((c = *p) != '!' && c != ';' && c != '#' && c != ','
+ 		&& !is_end_of_line[c]);
+ 	       p++)
+ 	    ;
+ 
+ 	  /* Parse !relocation_type */
+ 	  len = p - input_line_pointer;
+ 	  if (len == 0)
+ 	    {
+ 	      as_bad (_("No relocation operand"));
+ 	      goto err_report;
+ 	    }
+ 
+ 	  if (c != '!')
+ 	    {
+ 	      as_bad (_("No !sequence-number after !%s"), input_line_pointer);
+ 	      goto err_report;
+ 	    }
+ 
+ 	  r = &alpha_reloc_op[0];
+ 	  for (i = alpha_num_reloc_op-1; i >= 0; i--, r++)
+ 	    {
+ 	      if (len == r->length
+ 		  && memcmp (input_line_pointer, r->name, len) == 0)
+ 		break;
+ 	    }
+ 	  if (i < 0)
+ 	    {
+ 	      as_bad (_("Unknown relocation operand: !%s"), input_line_pointer);
+ 	      goto err_report;
+ 	    }
+ 
+ 	  input_line_pointer = ++p;
+ 
+ 	  /* Parse !sequence_number */
+ 	  memset (tok, '\0', sizeof (expressionS));
+ 	  expression (tok);
+ 
+ 	  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;
+ 	    }
+ 
+ 	  tok->X_op = r->op;
+ 	  reloc_found_p = 1;
+ 	  ++tok;
+ 	  break;
+ #endif
+ 
  	case ',':
  	  ++input_line_pointer;
  	  if (saw_comma || !saw_arg)
*************** tokenize_arguments (str, tok, ntok)
*** 1555,1560 ****
--- 2021,2027 ----
  	default:
  	  if (saw_arg && !saw_comma)
  	    goto err;
+ 
  	  expression (tok);
  	  if (tok->X_op == O_illegal || tok->X_op == O_absent)
  	    goto err;
*************** fini:
*** 1570,1580 ****
    if (saw_comma)
      goto err;
    input_line_pointer = old_input_line_pointer;
    return ntok - (end_tok - tok);
  
  err:
    input_line_pointer = old_input_line_pointer;
!   return -1;
  }
  
  /* Search forward through all variants of an opcode looking for a
--- 2037,2058 ----
    if (saw_comma)
      goto err;
    input_line_pointer = old_input_line_pointer;
+ 
+ #ifdef DEBUG_ALPHA
+   debug_exp (orig_tok, ntok - (end_tok - tok));
+ #endif
+ 
    return ntok - (end_tok - tok);
  
  err:
    input_line_pointer = old_input_line_pointer;
!   return TOKENIZE_ERROR;
! 
! #ifdef RELOC_OP_P
! err_report:
!   input_line_pointer = old_input_line_pointer;
!   return TOKENIZE_ERROR_REPORT;
! #endif
  }
  
  /* Search forward through all variants of an opcode looking for a
*************** find_macro_match(first_macro, tok, pntok
*** 1712,1735 ****
--- 2190,2227 ----
  		tokidx = 0;
  	      break;
  
+ 	      /* index register */
  	    case MACRO_IR:
  	      if (tokidx >= ntok || tok[tokidx].X_op != O_register
  		  || !is_ir_num(tok[tokidx].X_add_number))
  		goto match_failed;
  	      ++tokidx;
  	      break;
+ 
+ 	      /* parenthesized index register */
  	    case MACRO_PIR:
  	      if (tokidx >= ntok || tok[tokidx].X_op != O_pregister
  		  || !is_ir_num(tok[tokidx].X_add_number))
  		goto match_failed;
  	      ++tokidx;
  	      break;
+ 
+ 	      /* optional parenthesized index register */
+ 	    case MACRO_OPIR:
+ 	      if (tokidx < ntok && tok[tokidx].X_op == O_pregister
+ 		  && is_ir_num(tok[tokidx].X_add_number))
+ 		++tokidx;
+ 	      break;
+ 
+ 	      /* leading comma with a parenthesized index register */
  	    case MACRO_CPIR:
  	      if (tokidx >= ntok || tok[tokidx].X_op != O_cpregister
  		  || !is_ir_num(tok[tokidx].X_add_number))
  		goto match_failed;
  	      ++tokidx;
  	      break;
+ 
+ 	      /* floating point register */
  	    case MACRO_FPR:
  	      if (tokidx >= ntok || tok[tokidx].X_op != O_register
  		  || !is_fpr_num(tok[tokidx].X_add_number))
*************** find_macro_match(first_macro, tok, pntok
*** 1737,1742 ****
--- 2229,2235 ----
  	      ++tokidx;
  	      break;
  
+ 	      /* normal expression */
  	    case MACRO_EXP:
  	      if (tokidx >= ntok)
  		goto match_failed;
*************** find_macro_match(first_macro, tok, pntok
*** 1747,1752 ****
--- 2240,2254 ----
  		case O_register:
  		case O_pregister:
  		case O_cpregister:
+ #ifdef RELOC_OP_P
+ 		case O_literal:
+ 		case O_lituse_base:
+ 		case O_lituse_bytoff:
+ 		case O_lituse_jsr:
+ 		case O_gpdisp:
+ 		case O_gprelhigh:
+ 		case O_gprellow:
+ #endif
  		  goto match_failed;
  
  		default:
*************** find_macro_match(first_macro, tok, pntok
*** 1755,1760 ****
--- 2257,2294 ----
  	      ++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;
*************** emit_insn (insn)
*** 1940,1945 ****
--- 2474,2483 ----
        struct alpha_fixup *fixup = &insn->fixups[i];
        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)
*************** emit_insn (insn)
*** 1948,1976 ****
  	  size = 4;
  	  pcrel = ((operand->flags & AXP_OPERAND_RELATIVE) != 0);
  	}
! #ifdef OBJ_ELF
!       /* These relocation types are only used internally. */
!       else if (fixup->reloc == BFD_RELOC_ALPHA_GPDISP_HI16
! 	       || fixup->reloc == BFD_RELOC_ALPHA_GPDISP_LO16)
  	{
! 	  size = 2, pcrel = 0;
! 	}
  #endif
!       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;
  	}
-       assert (size >= 1 && size <= 4);
  
        fixP = fix_new_exp (frag_now, f - frag_now->fr_literal, size,
  			  &fixup->exp, pcrel, fixup->reloc);
  
!       /* Turn off complaints that the addend is too large for some fixups */
        switch (fixup->reloc)
  	{
  	case BFD_RELOC_ALPHA_GPDISP_LO16:
--- 2486,2533 ----
  	  size = 4;
  	  pcrel = ((operand->flags & AXP_OPERAND_RELATIVE) != 0);
  	}
!       else switch (fixup->reloc)
  	{
! #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);
  
! 	    size = bfd_get_reloc_size (reloc_howto);
! 	    pcrel = reloc_howto->pc_relative;
! 	  }
! 	  assert (size >= 1 && size <= 4);
! 	  break;
  	}
  
        fixP = fix_new_exp (frag_now, f - frag_now->fr_literal, size,
  			  &fixup->exp, pcrel, fixup->reloc);
  
!       /* Turn off complaints that the addend is too large for some fixups,
!          and copy in the sequence number for the explicit relocations.  */
        switch (fixup->reloc)
  	{
  	case BFD_RELOC_ALPHA_GPDISP_LO16:
*************** emit_insn (insn)
*** 1984,1989 ****
--- 2541,2609 ----
  	  fixP->fx_no_overflow = 1;
  	  break;
  
+ #ifdef RELOC_OP_P
+ 	case BFD_RELOC_ALPHA_USER_LITERAL:
+ 	  fixP->fx_no_overflow = 1;
+ 	  sprintf (buffer, "!%u", insn->sequence[i]);
+ 	  info = ((struct alpha_literal_tag *)
+ 		  hash_find (alpha_literal_hash, buffer));
+ 
+ 	  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->n_literals;
+ 
+ 	  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)
+ 	    {
+ 	      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->n_lituses++;
+ 	  fixP->tc_fix_data.info = info;
+ 	  fixP->tc_fix_data.next_lituse = info->lituse;
+ 	  info->lituse = fixP;
+ 	  if (info->segment != now_seg)
+ 	    info->multi_section_p = 1;
+ 
+ 	  break;
+ #endif
+ 
  	default:
  	  if ((int)fixup->reloc < 0)
  	    {
*************** assemble_tokens (opname, tok, ntok, loca
*** 2063,2068 ****
--- 2683,2699 ----
  	}
      }
  
+ #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)
*************** FIXME
*** 2119,2124 ****
--- 2750,2766 ----
    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);
*************** add_to_link_pool (basesym, sym, addend)
*** 2232,2246 ****
     i.e. "ldq $targ, LIT($gp); addq $targ, $0, $targ".  Odd, perhaps,
     but this is what OSF/1 does.
  
     Finally, the return value is true if the calling macro may emit a
     LITUSE reloc if otherwise appropriate.  */
  
  static int
! load_expression (targreg, exp, pbasereg, poffset)
       int targreg;
       const expressionS *exp;
       int *pbasereg;
       expressionS *poffset;
  {
    int emit_lituse = 0;
    offsetT addend = exp->X_add_number;
--- 2874,2892 ----
     i.e. "ldq $targ, LIT($gp); addq $targ, $0, $targ".  Odd, perhaps,
     but this is what OSF/1 does.
  
+    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.  */
  
  static int
! load_expression (targreg, exp, pbasereg, poffset, explicit_reloc)
       int targreg;
       const expressionS *exp;
       int *pbasereg;
       expressionS *poffset;
+      const expressionS *explicit_reloc;
  {
    int emit_lituse = 0;
    offsetT addend = exp->X_add_number;
*************** load_expression (targreg, exp, pbasereg,
*** 2292,2297 ****
--- 2938,2944 ----
  
  	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;
  #endif /* OBJ_ECOFF */
*************** load_expression (targreg, exp, pbasereg,
*** 2329,2341 ****
  	assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
  
  	assert (insn.nfixups == 1);
! 	insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL;
  #endif /* OBJ_ELF */
  #ifdef OBJ_EVAX
  	offsetT link;
  
  	/* Find symbol or symbol pointer in link section.  */
  
  	if (exp->X_add_symbol == alpha_evax_proc.symbol)
  	  {
  	    if (range_signed_16 (addend))
--- 2976,3000 ----
  	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
! 	  }
  #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))
*************** load_expression (targreg, exp, pbasereg,
*** 2394,2405 ****
--- 3053,3066 ----
        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);
*************** load_expression (targreg, exp, pbasereg,
*** 2507,2513 ****
        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 = 1;
        emit_lituse = 0;
  
        emit_insn (&insn);
--- 3168,3174 ----
        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;
        emit_lituse = 0;
  
        emit_insn (&insn);
*************** load_expression (targreg, exp, pbasereg,
*** 2587,2605 ****
     large constants.  */
  
  static void
! emit_lda (tok, ntok, unused)
       const expressionS *tok;
       int ntok;
!      const PTR unused ATTRIBUTE_UNUSED;
  {
    int basereg;
  
    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);
  }
  
  /* The ldah macro differs from the ldah instruction in that it has $31
--- 3248,3313 ----
     large constants.  */
  
  static void
! emit_lda (tok, ntok, opname)
       const expressionS *tok;
       int ntok;
!      const PTR opname;
  {
    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!%d"), r->name,
+ 		      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);
  }
  
  /* The ldah macro differs from the ldah instruction in that it has $31
*************** emit_ldah (tok, ntok, unused)
*** 2613,2618 ****
--- 3321,3337 ----
  {
    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);
*************** emit_ir_load (tok, ntok, opname)
*** 2634,2652 ****
    expressionS newtok[3];
    struct alpha_insn insn;
  
    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]);
  
    newtok[0] = tok[0];
    set_tok_preg (newtok[2], basereg);
  
    assemble_tokens_to_insn ((const char *)opname, newtok, 3, &insn);
  
    if (lituse)
      {
        assert (insn.nfixups < MAX_INSN_FIXUPS);
--- 3353,3418 ----
    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[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);
*************** emit_ir_load (tok, ntok, opname)
*** 2659,2665 ****
        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 = 1;
      }
  
    emit_insn (&insn);
--- 3425,3431 ----
        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;
      }
  
    emit_insn (&insn);
*************** emit_loadstore (tok, ntok, opname)
*** 2678,2683 ****
--- 3444,3464 ----
    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
*************** emit_loadstore (tok, ntok, opname)
*** 2688,2694 ****
        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]);
      }
    else
      {
--- 3469,3476 ----
        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);
      }
    else
      {
*************** emit_loadstore (tok, ntok, opname)
*** 2701,2706 ****
--- 3483,3504 ----
  
    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);
*************** emit_loadstore (tok, ntok, opname)
*** 2713,2719 ****
        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 = 1;
      }
  
    emit_insn (&insn);
--- 3511,3517 ----
        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;
      }
  
    emit_insn (&insn);
*************** emit_ldXu (tok, ntok, vlgsize)
*** 2733,2738 ****
--- 3531,3549 ----
      {
        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
+ 
        if (alpha_noat_on)
  	as_bad (_("macro requires $at register while noat in effect"));
  
*************** emit_ldil (tok, ntok, unused)
*** 2848,2853 ****
--- 3659,3675 ----
  {
    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);
  
*************** emit_sextX (tok, ntok, vlgsize)
*** 3012,3017 ****
--- 3834,3852 ----
        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];
*************** emit_division (tok, ntok, symname)
*** 3058,3063 ****
--- 3893,3909 ----
    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);
  
*************** emit_division (tok, ntok, symname)
*** 3157,3162 ****
--- 4003,4019 ----
    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);
  
*************** emit_jsrjmp (tok, ntok, vopname)
*** 3253,3258 ****
--- 4110,4126 ----
    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
+ 
    if (tokidx < ntok && tok[tokidx].X_op == O_register)
      r = regno (tok[tokidx++].X_add_number);
    else
*************** emit_jsrjmp (tok, ntok, vopname)
*** 3269,3275 ****
    else
      {
        int basereg = alpha_gp_register;
!       lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], &basereg, NULL);
      }
  #endif
  
--- 4137,4144 ----
    else
      {
        int basereg = alpha_gp_register;
!       lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], &basereg, NULL,
! 				(const expressionS *)0);
      }
  #endif
  
*************** emit_jsrjmp (tok, ntok, vopname)
*** 3299,3305 ****
        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 = 3;
      }
  
    emit_insn (&insn);
--- 4168,4174 ----
        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;
      }
  
    emit_insn (&insn);
*************** emit_retjcr (tok, ntok, vopname)
*** 3317,3322 ****
--- 4186,4202 ----
    const char *opname = (const char *)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);
*** gas/config/tc-alpha.h.~1~	Mon Nov 22 13:32:33 1999
--- gas/config/tc-alpha.h	Fri Nov 19 13:30:03 1999
*************** extern void alpha_frob_file_before_adjus
*** 102,104 ****
--- 102,148 ----
    { ".sdata",   SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL  }, \
    { ".sbss",    SHT_NOBITS,     SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL  },
  #endif
+ 
+ /* Whether to add support for explict !relocation_op!sequence_number.  At the
+    moment, only do this for ELF, though ECOFF could use it as well.  */
+ 
+ #ifdef OBJ_ELF
+ #define RELOC_OP_P
+ #endif
+ 
+ #ifdef RELOC_OP_P
+ /* Before the relocations are written, reorder them, so that user supplied
+    !lituse relocations follow the appropriate !literal relocations.  Also
+    convert the gas-internal relocations to the appropriate linker relocations.
+    */
+ #define tc_adjust_symtab() alpha_adjust_symtab ()
+ extern void alpha_adjust_symtab PARAMS ((void));
+ 
+ /* New fields for supporting explicit relocations (such as !literal to mark
+    where a pointer is loaded from the global table, and !lituse_base to track
+    all of the normal uses of that pointer).  */
+ 
+ #define TC_FIX_TYPE struct alpha_fix_tag
+ 
+ struct alpha_fix_tag
+ {
+   struct fix *next_lituse;		/* next !lituse */
+   struct alpha_literal_tag *info;	/* other members with same sequence */
+ };
+ 
+ /* Initialize the TC_FIX_TYPE field.  */
+ #define TC_INIT_FIX_DATA(fixP)						\
+ do {									\
+   fixP->tc_fix_data.next_lituse = (struct fix *)0;			\
+   fixP->tc_fix_data.info = (struct alpha_literal_tag *)0;		\
+ } while (0)
+ 
+ /* Work with DEBUG5 to print fields in tc_fix_type.  */
+ #define TC_FIX_DATA_PRINT(stream,fixP)					\
+ do {									\
+   if (fixP->tc_fix_data.info)						\
+     fprintf (stderr, "\tinfo = 0x%lx, next_lituse = 0x%lx\n", \
+ 	     (long)fixP->tc_fix_data.info,				\
+ 	     (long)fixP->tc_fix_data.next_lituse);			\
+ } while (0)
+ #endif

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]