133965Sjdp/* tc-alpha.c - Processor-specific code for the DEC Alpha AXP CPU.
2104834Sobrien   Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
3218822Sdim   2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
433965Sjdp   Contributed by Carnegie Mellon University, 1993.
533965Sjdp   Written by Alessandro Forin, based on earlier gas-1.38 target CPU files.
633965Sjdp   Modified by Ken Raeburn for gas-2.x and ECOFF support.
733965Sjdp   Modified by Richard Henderson for ELF support.
860484Sobrien   Modified by Klaus K"ampf for EVAX (OpenVMS/Alpha) support.
933965Sjdp
1033965Sjdp   This file is part of GAS, the GNU Assembler.
1133965Sjdp
1233965Sjdp   GAS is free software; you can redistribute it and/or modify
1333965Sjdp   it under the terms of the GNU General Public License as published by
1433965Sjdp   the Free Software Foundation; either version 2, or (at your option)
1533965Sjdp   any later version.
1633965Sjdp
1733965Sjdp   GAS is distributed in the hope that it will be useful,
1833965Sjdp   but WITHOUT ANY WARRANTY; without even the implied warranty of
1933965Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2033965Sjdp   GNU General Public License for more details.
2133965Sjdp
2233965Sjdp   You should have received a copy of the GNU General Public License
2333965Sjdp   along with GAS; see the file COPYING.  If not, write to the Free
24218822Sdim   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
25218822Sdim   02110-1301, USA.  */
2633965Sjdp
27218822Sdim/* Mach Operating System
28218822Sdim   Copyright (c) 1993 Carnegie Mellon University
29218822Sdim   All Rights Reserved.
3033965Sjdp
31218822Sdim   Permission to use, copy, modify and distribute this software and its
32218822Sdim   documentation is hereby granted, provided that both the copyright
33218822Sdim   notice and this permission notice appear in all copies of the
34218822Sdim   software, derivative works or modified versions, and any portions
35218822Sdim   thereof, and that both notices appear in supporting documentation.
36218822Sdim
37218822Sdim   CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
38218822Sdim   CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
39218822Sdim   ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
40218822Sdim
41218822Sdim   Carnegie Mellon requests users of this software to return to
42218822Sdim
43218822Sdim    Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
44218822Sdim    School of Computer Science
45218822Sdim    Carnegie Mellon University
46218822Sdim    Pittsburgh PA 15213-3890
47218822Sdim
48218822Sdim   any improvements or extensions that they make and grant Carnegie the
49218822Sdim   rights to redistribute these changes.  */
50218822Sdim
5133965Sjdp#include "as.h"
5233965Sjdp#include "subsegs.h"
5360484Sobrien#include "struc-symbol.h"
5460484Sobrien#include "ecoff.h"
5533965Sjdp
5633965Sjdp#include "opcode/alpha.h"
5733965Sjdp
5833965Sjdp#ifdef OBJ_ELF
5933965Sjdp#include "elf/alpha.h"
6077298Sobrien#include "dwarf2dbg.h"
6133965Sjdp#endif
6233965Sjdp
63218822Sdim#include "dw2gencfi.h"
6489857Sobrien#include "safe-ctype.h"
6533965Sjdp
66130561Sobrien/* Local types.  */
6733965Sjdp
68218822Sdim#define TOKENIZE_ERROR 		-1
69218822Sdim#define TOKENIZE_ERROR_REPORT	-2
70218822Sdim#define MAX_INSN_FIXUPS		 2
71218822Sdim#define MAX_INSN_ARGS		 5
7260484Sobrien
73130561Sobrienstruct alpha_fixup
74130561Sobrien{
7533965Sjdp  expressionS exp;
7633965Sjdp  bfd_reloc_code_real_type reloc;
7733965Sjdp};
7833965Sjdp
79130561Sobrienstruct alpha_insn
80130561Sobrien{
8133965Sjdp  unsigned insn;
8233965Sjdp  int nfixups;
8333965Sjdp  struct alpha_fixup fixups[MAX_INSN_FIXUPS];
8489857Sobrien  long sequence;
8533965Sjdp};
8633965Sjdp
87130561Sobrienenum alpha_macro_arg
88130561Sobrien  {
89130561Sobrien    MACRO_EOA = 1,
90130561Sobrien    MACRO_IR,
91130561Sobrien    MACRO_PIR,
92130561Sobrien    MACRO_OPIR,
93130561Sobrien    MACRO_CPIR,
94130561Sobrien    MACRO_FPR,
95130561Sobrien    MACRO_EXP,
96130561Sobrien  };
9733965Sjdp
98130561Sobrienstruct alpha_macro
99130561Sobrien{
10033965Sjdp  const char *name;
101218822Sdim  void (*emit) (const expressionS *, int, const void *);
102218822Sdim  const void * arg;
10333965Sjdp  enum alpha_macro_arg argsets[16];
10433965Sjdp};
10533965Sjdp
10677298Sobrien/* Extra expression types.  */
10733965Sjdp
108218822Sdim#define O_pregister	O_md1	/* O_register, in parentheses.  */
109218822Sdim#define O_cpregister	O_md2	/* + a leading comma.  */
11033965Sjdp
111104834Sobrien/* The alpha_reloc_op table below depends on the ordering of these.  */
112218822Sdim#define O_literal	O_md3		/* !literal relocation.  */
113218822Sdim#define O_lituse_addr	O_md4		/* !lituse_addr relocation.  */
114218822Sdim#define O_lituse_base	O_md5		/* !lituse_base relocation.  */
115218822Sdim#define O_lituse_bytoff	O_md6		/* !lituse_bytoff relocation.  */
116218822Sdim#define O_lituse_jsr	O_md7		/* !lituse_jsr relocation.  */
117218822Sdim#define O_lituse_tlsgd	O_md8		/* !lituse_tlsgd relocation.  */
118218822Sdim#define O_lituse_tlsldm	O_md9		/* !lituse_tlsldm relocation.  */
119218822Sdim#define O_lituse_jsrdirect O_md10	/* !lituse_jsrdirect relocation.  */
120218822Sdim#define O_gpdisp	O_md11		/* !gpdisp relocation.  */
121218822Sdim#define O_gprelhigh	O_md12		/* !gprelhigh relocation.  */
122218822Sdim#define O_gprellow	O_md13		/* !gprellow relocation.  */
123218822Sdim#define O_gprel		O_md14		/* !gprel relocation.  */
124218822Sdim#define O_samegp	O_md15		/* !samegp relocation.  */
125218822Sdim#define O_tlsgd		O_md16		/* !tlsgd relocation.  */
126218822Sdim#define O_tlsldm	O_md17		/* !tlsldm relocation.  */
127218822Sdim#define O_gotdtprel	O_md18		/* !gotdtprel relocation.  */
128218822Sdim#define O_dtprelhi	O_md19		/* !dtprelhi relocation.  */
129218822Sdim#define O_dtprello	O_md20		/* !dtprello relocation.  */
130218822Sdim#define O_dtprel	O_md21		/* !dtprel relocation.  */
131218822Sdim#define O_gottprel	O_md22		/* !gottprel relocation.  */
132218822Sdim#define O_tprelhi	O_md23		/* !tprelhi relocation.  */
133218822Sdim#define O_tprello	O_md24		/* !tprello relocation.  */
134218822Sdim#define O_tprel		O_md25		/* !tprel relocation.  */
13560484Sobrien
13689857Sobrien#define DUMMY_RELOC_LITUSE_ADDR		(BFD_RELOC_UNUSED + 1)
13789857Sobrien#define DUMMY_RELOC_LITUSE_BASE		(BFD_RELOC_UNUSED + 2)
13889857Sobrien#define DUMMY_RELOC_LITUSE_BYTOFF	(BFD_RELOC_UNUSED + 3)
13989857Sobrien#define DUMMY_RELOC_LITUSE_JSR		(BFD_RELOC_UNUSED + 4)
140104834Sobrien#define DUMMY_RELOC_LITUSE_TLSGD	(BFD_RELOC_UNUSED + 5)
141104834Sobrien#define DUMMY_RELOC_LITUSE_TLSLDM	(BFD_RELOC_UNUSED + 6)
142218822Sdim#define DUMMY_RELOC_LITUSE_JSRDIRECT	(BFD_RELOC_UNUSED + 7)
14360484Sobrien
144104834Sobrien#define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_tprel)
14589857Sobrien
146130561Sobrien/* Macros for extracting the type and number of encoded register tokens.  */
14733965Sjdp
14833965Sjdp#define is_ir_num(x)		(((x) & 32) == 0)
14933965Sjdp#define is_fpr_num(x)		(((x) & 32) != 0)
15033965Sjdp#define regno(x)		((x) & 31)
15133965Sjdp
152130561Sobrien/* Something odd inherited from the old assembler.  */
15333965Sjdp
15433965Sjdp#define note_gpreg(R)		(alpha_gprmask |= (1 << (R)))
15533965Sjdp#define note_fpreg(R)		(alpha_fprmask |= (1 << (R)))
15633965Sjdp
15733965Sjdp/* Predicates for 16- and 32-bit ranges */
15838889Sjdp/* XXX: The non-shift version appears to trigger a compiler bug when
15938889Sjdp   cross-assembling from x86 w/ gcc 2.7.2.  */
16033965Sjdp
16138889Sjdp#if 1
16238889Sjdp#define range_signed_16(x) \
16377298Sobrien	(((offsetT) (x) >> 15) == 0 || ((offsetT) (x) >> 15) == -1)
16438889Sjdp#define range_signed_32(x) \
16577298Sobrien	(((offsetT) (x) >> 31) == 0 || ((offsetT) (x) >> 31) == -1)
16638889Sjdp#else
16777298Sobrien#define range_signed_16(x)	((offsetT) (x) >= -(offsetT) 0x8000 &&	\
16877298Sobrien				 (offsetT) (x) <=  (offsetT) 0x7FFF)
16977298Sobrien#define range_signed_32(x)	((offsetT) (x) >= -(offsetT) 0x80000000 && \
17077298Sobrien				 (offsetT) (x) <=  (offsetT) 0x7FFFFFFF)
17138889Sjdp#endif
17233965Sjdp
17333965Sjdp/* Macros for sign extending from 16- and 32-bits.  */
17433965Sjdp/* XXX: The cast macros will work on all the systems that I care about,
17533965Sjdp   but really a predicate should be found to use the non-cast forms.  */
17633965Sjdp
17733965Sjdp#if 1
17877298Sobrien#define sign_extend_16(x)	((short) (x))
17977298Sobrien#define sign_extend_32(x)	((int) (x))
18033965Sjdp#else
18177298Sobrien#define sign_extend_16(x)	((offsetT) (((x) & 0xFFFF) ^ 0x8000) - 0x8000)
18277298Sobrien#define sign_extend_32(x)	((offsetT) (((x) & 0xFFFFFFFF) \
18333965Sjdp					   ^ 0x80000000) - 0x80000000)
18433965Sjdp#endif
18533965Sjdp
186130561Sobrien/* Macros to build tokens.  */
18733965Sjdp
18877298Sobrien#define set_tok_reg(t, r)	(memset (&(t), 0, sizeof (t)),		\
18933965Sjdp				 (t).X_op = O_register,			\
19033965Sjdp				 (t).X_add_number = (r))
19177298Sobrien#define set_tok_preg(t, r)	(memset (&(t), 0, sizeof (t)),		\
19233965Sjdp				 (t).X_op = O_pregister,		\
19333965Sjdp				 (t).X_add_number = (r))
19477298Sobrien#define set_tok_cpreg(t, r)	(memset (&(t), 0, sizeof (t)),		\
19533965Sjdp				 (t).X_op = O_cpregister,		\
19633965Sjdp				 (t).X_add_number = (r))
19777298Sobrien#define set_tok_freg(t, r)	(memset (&(t), 0, sizeof (t)),		\
19833965Sjdp				 (t).X_op = O_register,			\
19977298Sobrien				 (t).X_add_number = (r) + 32)
20077298Sobrien#define set_tok_sym(t, s, a)	(memset (&(t), 0, sizeof (t)),		\
20133965Sjdp				 (t).X_op = O_symbol,			\
20233965Sjdp				 (t).X_add_symbol = (s),		\
20333965Sjdp				 (t).X_add_number = (a))
20477298Sobrien#define set_tok_const(t, n)	(memset (&(t), 0, sizeof (t)),		\
20533965Sjdp				 (t).X_op = O_constant,			\
20633965Sjdp				 (t).X_add_number = (n))
20733965Sjdp
20833965Sjdp/* Generic assembler global variables which must be defined by all
20933965Sjdp   targets.  */
21033965Sjdp
21133965Sjdp/* Characters which always start a comment.  */
21233965Sjdpconst char comment_chars[] = "#";
21333965Sjdp
21433965Sjdp/* Characters which start a comment at the beginning of a line.  */
21533965Sjdpconst char line_comment_chars[] = "#";
21633965Sjdp
21733965Sjdp/* Characters which may be used to separate multiple commands on a
21833965Sjdp   single line.  */
21933965Sjdpconst char line_separator_chars[] = ";";
22033965Sjdp
22133965Sjdp/* Characters which are used to indicate an exponent in a floating
22233965Sjdp   point number.  */
22333965Sjdpconst char EXP_CHARS[] = "eE";
22433965Sjdp
22533965Sjdp/* Characters which mean that a number is a floating point constant,
22633965Sjdp   as in 0d1.0.  */
22733965Sjdp/* XXX: Do all of these really get used on the alpha??  */
22833965Sjdpchar FLT_CHARS[] = "rRsSfFdDxXpP";
22933965Sjdp
23033965Sjdp#ifdef OBJ_EVAX
23138889Sjdpconst char *md_shortopts = "Fm:g+1h:HG:";
23233965Sjdp#else
23338889Sjdpconst char *md_shortopts = "Fm:gG:";
23433965Sjdp#endif
23533965Sjdp
236130561Sobrienstruct option md_longopts[] =
237130561Sobrien  {
23833965Sjdp#define OPTION_32ADDR (OPTION_MD_BASE)
239130561Sobrien    { "32addr", no_argument, NULL, OPTION_32ADDR },
24077298Sobrien#define OPTION_RELAX (OPTION_32ADDR + 1)
241130561Sobrien    { "relax", no_argument, NULL, OPTION_RELAX },
24260484Sobrien#ifdef OBJ_ELF
24377298Sobrien#define OPTION_MDEBUG (OPTION_RELAX + 1)
24477298Sobrien#define OPTION_NO_MDEBUG (OPTION_MDEBUG + 1)
245130561Sobrien    { "mdebug", no_argument, NULL, OPTION_MDEBUG },
246130561Sobrien    { "no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG },
24760484Sobrien#endif
248130561Sobrien    { NULL, no_argument, NULL, 0 }
249130561Sobrien  };
25033965Sjdp
25177298Sobriensize_t md_longopts_size = sizeof (md_longopts);
25233965Sjdp
25333965Sjdp#ifdef OBJ_EVAX
25433965Sjdp#define AXP_REG_R0     0
25533965Sjdp#define AXP_REG_R16    16
25633965Sjdp#define AXP_REG_R17    17
25733965Sjdp#undef AXP_REG_T9
25833965Sjdp#define AXP_REG_T9     22
25933965Sjdp#undef AXP_REG_T10
26033965Sjdp#define AXP_REG_T10    23
26133965Sjdp#undef AXP_REG_T11
26233965Sjdp#define AXP_REG_T11    24
26333965Sjdp#undef AXP_REG_T12
26433965Sjdp#define AXP_REG_T12    25
26533965Sjdp#define AXP_REG_AI     25
26633965Sjdp#undef AXP_REG_FP
26733965Sjdp#define AXP_REG_FP     29
26833965Sjdp
26933965Sjdp#undef AXP_REG_GP
27033965Sjdp#define AXP_REG_GP AXP_REG_PV
27133965Sjdp#endif /* OBJ_EVAX  */
27233965Sjdp
273130561Sobrien/* The cpu for which we are generating code.  */
27433965Sjdpstatic unsigned alpha_target = AXP_OPCODE_BASE;
27533965Sjdpstatic const char *alpha_target_name = "<all>";
27633965Sjdp
277130561Sobrien/* The hash table of instruction opcodes.  */
27833965Sjdpstatic struct hash_control *alpha_opcode_hash;
27933965Sjdp
280130561Sobrien/* The hash table of macro opcodes.  */
28133965Sjdpstatic struct hash_control *alpha_macro_hash;
28233965Sjdp
28333965Sjdp#ifdef OBJ_ECOFF
284130561Sobrien/* The $gp relocation symbol.  */
28533965Sjdpstatic symbolS *alpha_gp_symbol;
28633965Sjdp
28733965Sjdp/* XXX: what is this, and why is it exported? */
28833965SjdpvalueT alpha_gp_value;
28933965Sjdp#endif
29033965Sjdp
291130561Sobrien/* The current $gp register.  */
29233965Sjdpstatic int alpha_gp_register = AXP_REG_GP;
29333965Sjdp
294130561Sobrien/* A table of the register symbols.  */
29533965Sjdpstatic symbolS *alpha_register_table[64];
29633965Sjdp
297130561Sobrien/* Constant sections, or sections of constants.  */
29833965Sjdp#ifdef OBJ_ECOFF
29933965Sjdpstatic segT alpha_lita_section;
30033965Sjdp#endif
30133965Sjdp#ifdef OBJ_EVAX
30233965Sjdpstatic segT alpha_link_section;
30333965Sjdpstatic segT alpha_ctors_section;
30433965Sjdpstatic segT alpha_dtors_section;
30533965Sjdp#endif
30633965Sjdpstatic segT alpha_lit8_section;
30733965Sjdp
30877298Sobrien/* Symbols referring to said sections.  */
30933965Sjdp#ifdef OBJ_ECOFF
31033965Sjdpstatic symbolS *alpha_lita_symbol;
31133965Sjdp#endif
31233965Sjdp#ifdef OBJ_EVAX
31333965Sjdpstatic symbolS *alpha_link_symbol;
31433965Sjdpstatic symbolS *alpha_ctors_symbol;
31533965Sjdpstatic symbolS *alpha_dtors_symbol;
31633965Sjdp#endif
31733965Sjdpstatic symbolS *alpha_lit8_symbol;
31833965Sjdp
319130561Sobrien/* Literal for .litX+0x8000 within .lita.  */
32033965Sjdp#ifdef OBJ_ECOFF
32133965Sjdpstatic offsetT alpha_lit8_literal;
32233965Sjdp#endif
32333965Sjdp
324130561Sobrien/* Is the assembler not allowed to use $at?  */
32533965Sjdpstatic int alpha_noat_on = 0;
32633965Sjdp
327130561Sobrien/* Are macros enabled?  */
32833965Sjdpstatic int alpha_macros_on = 1;
32933965Sjdp
330130561Sobrien/* Are floats disabled?  */
33133965Sjdpstatic int alpha_nofloats_on = 0;
33233965Sjdp
333130561Sobrien/* Are addresses 32 bit?  */
33433965Sjdpstatic int alpha_addr32_on = 0;
33533965Sjdp
33633965Sjdp/* Symbol labelling the current insn.  When the Alpha gas sees
33733965Sjdp     foo:
33833965Sjdp       .quad 0
33933965Sjdp   and the section happens to not be on an eight byte boundary, it
34033965Sjdp   will align both the symbol and the .quad to an eight byte boundary.  */
34133965Sjdpstatic symbolS *alpha_insn_label;
34233965Sjdp
34333965Sjdp/* Whether we should automatically align data generation pseudo-ops.
34433965Sjdp   .align 0 will turn this off.  */
34533965Sjdpstatic int alpha_auto_align_on = 1;
34633965Sjdp
34733965Sjdp/* The known current alignment of the current section.  */
34833965Sjdpstatic int alpha_current_align;
34933965Sjdp
35033965Sjdp/* These are exported to ECOFF code.  */
35133965Sjdpunsigned long alpha_gprmask, alpha_fprmask;
35233965Sjdp
35333965Sjdp/* Whether the debugging option was seen.  */
35433965Sjdpstatic int alpha_debug;
35533965Sjdp
35660484Sobrien#ifdef OBJ_ELF
35760484Sobrien/* Whether we are emitting an mdebug section.  */
35877298Sobrienint alpha_flag_mdebug = -1;
35960484Sobrien#endif
36060484Sobrien
36138889Sjdp/* Don't fully resolve relocations, allowing code movement in the linker.  */
36238889Sjdpstatic int alpha_flag_relax;
36338889Sjdp
36438889Sjdp/* What value to give to bfd_set_gp_size.  */
36538889Sjdpstatic int g_switch_value = 8;
36638889Sjdp
36733965Sjdp#ifdef OBJ_EVAX
36833965Sjdp/* Collect information about current procedure here.  */
369218822Sdimstatic struct
370218822Sdim{
371218822Sdim  symbolS *symbol;	/* Proc pdesc symbol.  */
37233965Sjdp  int pdsckind;
373218822Sdim  int framereg;		/* Register for frame pointer.  */
374218822Sdim  int framesize;	/* Size of frame.  */
37533965Sjdp  int rsa_offset;
37633965Sjdp  int ra_save;
37733965Sjdp  int fp_save;
37833965Sjdp  long imask;
37933965Sjdp  long fmask;
38033965Sjdp  int type;
38133965Sjdp  int prologue;
38233965Sjdp} alpha_evax_proc;
38333965Sjdp
38433965Sjdpstatic int alpha_flag_hash_long_names = 0;		/* -+ */
38533965Sjdpstatic int alpha_flag_show_after_trunc = 0;		/* -H */
38633965Sjdp
38733965Sjdp/* If the -+ switch is given, then a hash is appended to any name that is
388130561Sobrien   longer than 64 characters, else longer symbol names are truncated.  */
38933965Sjdp
39033965Sjdp#endif
39133965Sjdp
39260484Sobrien#ifdef RELOC_OP_P
39360484Sobrien/* A table to map the spelling of a relocation operand into an appropriate
39460484Sobrien   bfd_reloc_code_real_type type.  The table is assumed to be ordered such
39560484Sobrien   that op-O_literal indexes into it.  */
39660484Sobrien
39760484Sobrien#define ALPHA_RELOC_TABLE(op)						\
39889857Sobrien(&alpha_reloc_op[ ((!USER_RELOC_P (op))					\
39960484Sobrien		  ? (abort (), 0)					\
40089857Sobrien		  : (int) (op) - (int) O_literal) ])
40160484Sobrien
40289857Sobrien#define DEF(NAME, RELOC, REQ, ALLOW) \
40389857Sobrien { #NAME, sizeof(#NAME)-1, O_##NAME, RELOC, REQ, ALLOW}
40460484Sobrien
405130561Sobrienstatic const struct alpha_reloc_op_tag
406130561Sobrien{
407218822Sdim  const char *name;				/* String to lookup.  */
408218822Sdim  size_t length;				/* Size of the string.  */
409218822Sdim  operatorT op;					/* Which operator to use.  */
410218822Sdim  bfd_reloc_code_real_type reloc;		/* Relocation before frob.  */
411218822Sdim  unsigned int require_seq : 1;			/* Require a sequence number.  */
412218822Sdim  unsigned int allow_seq : 1;			/* Allow a sequence number.  */
413130561Sobrien}
414130561Sobrienalpha_reloc_op[] =
415130561Sobrien{
416218822Sdim  DEF (literal, BFD_RELOC_ALPHA_ELF_LITERAL, 0, 1),
417218822Sdim  DEF (lituse_addr, DUMMY_RELOC_LITUSE_ADDR, 1, 1),
418218822Sdim  DEF (lituse_base, DUMMY_RELOC_LITUSE_BASE, 1, 1),
419218822Sdim  DEF (lituse_bytoff, DUMMY_RELOC_LITUSE_BYTOFF, 1, 1),
420218822Sdim  DEF (lituse_jsr, DUMMY_RELOC_LITUSE_JSR, 1, 1),
421218822Sdim  DEF (lituse_tlsgd, DUMMY_RELOC_LITUSE_TLSGD, 1, 1),
422218822Sdim  DEF (lituse_tlsldm, DUMMY_RELOC_LITUSE_TLSLDM, 1, 1),
423218822Sdim  DEF (lituse_jsrdirect, DUMMY_RELOC_LITUSE_JSRDIRECT, 1, 1),
424218822Sdim  DEF (gpdisp, BFD_RELOC_ALPHA_GPDISP, 1, 1),
425218822Sdim  DEF (gprelhigh, BFD_RELOC_ALPHA_GPREL_HI16, 0, 0),
426218822Sdim  DEF (gprellow, BFD_RELOC_ALPHA_GPREL_LO16, 0, 0),
427218822Sdim  DEF (gprel, BFD_RELOC_GPREL16, 0, 0),
428218822Sdim  DEF (samegp, BFD_RELOC_ALPHA_BRSGP, 0, 0),
429218822Sdim  DEF (tlsgd, BFD_RELOC_ALPHA_TLSGD, 0, 1),
430218822Sdim  DEF (tlsldm, BFD_RELOC_ALPHA_TLSLDM, 0, 1),
431218822Sdim  DEF (gotdtprel, BFD_RELOC_ALPHA_GOTDTPREL16, 0, 0),
432218822Sdim  DEF (dtprelhi, BFD_RELOC_ALPHA_DTPREL_HI16, 0, 0),
433218822Sdim  DEF (dtprello, BFD_RELOC_ALPHA_DTPREL_LO16, 0, 0),
434218822Sdim  DEF (dtprel, BFD_RELOC_ALPHA_DTPREL16, 0, 0),
435218822Sdim  DEF (gottprel, BFD_RELOC_ALPHA_GOTTPREL16, 0, 0),
436218822Sdim  DEF (tprelhi, BFD_RELOC_ALPHA_TPREL_HI16, 0, 0),
437218822Sdim  DEF (tprello, BFD_RELOC_ALPHA_TPREL_LO16, 0, 0),
438218822Sdim  DEF (tprel, BFD_RELOC_ALPHA_TPREL16, 0, 0),
43989857Sobrien};
44060484Sobrien
44189857Sobrien#undef DEF
44260484Sobrien
44360484Sobrienstatic const int alpha_num_reloc_op
44477298Sobrien  = sizeof (alpha_reloc_op) / sizeof (*alpha_reloc_op);
44589857Sobrien#endif /* RELOC_OP_P */
44660484Sobrien
447218822Sdim/* Maximum # digits needed to hold the largest sequence #.  */
44860484Sobrien#define ALPHA_RELOC_DIGITS 25
44960484Sobrien
450130561Sobrien/* Structure to hold explicit sequence information.  */
45189857Sobrienstruct alpha_reloc_tag
45260484Sobrien{
453218822Sdim  fixS *master;			/* The literal reloc.  */
454218822Sdim  fixS *slaves;			/* Head of linked list of lituses.  */
455218822Sdim  segT segment;			/* Segment relocs are in or undefined_section.  */
456218822Sdim  long sequence;		/* Sequence #.  */
457218822Sdim  unsigned n_master;		/* # of literals.  */
458218822Sdim  unsigned n_slaves;		/* # of lituses.  */
459218822Sdim  unsigned saw_tlsgd : 1;	/* True if ...  */
460104834Sobrien  unsigned saw_tlsldm : 1;
461104834Sobrien  unsigned saw_lu_tlsgd : 1;
462104834Sobrien  unsigned saw_lu_tlsldm : 1;
463218822Sdim  unsigned multi_section_p : 1;	/* True if more than one section was used.  */
464218822Sdim  char string[1];		/* Printable form of sequence to hash with.  */
46560484Sobrien};
46660484Sobrien
467218822Sdim/* Hash table to link up literals with the appropriate lituse.  */
46860484Sobrienstatic struct hash_control *alpha_literal_hash;
46989857Sobrien
47089857Sobrien/* Sequence numbers for internal use by macros.  */
47189857Sobrienstatic long next_sequence_num = -1;
47260484Sobrien
47338889Sjdp/* A table of CPU names and opcode sets.  */
47438889Sjdp
475130561Sobrienstatic const struct cpu_type
476130561Sobrien{
47738889Sjdp  const char *name;
47838889Sjdp  unsigned flags;
479130561Sobrien}
480130561Sobriencpu_types[] =
481130561Sobrien{
48238889Sjdp  /* Ad hoc convention: cpu number gets palcode, process code doesn't.
48377298Sobrien     This supports usage under DU 4.0b that does ".arch ev4", and
48438889Sjdp     usage in MILO that does -m21064.  Probably something more
48538889Sjdp     specific like -m21064-pal should be used, but oh well.  */
48638889Sjdp
48738889Sjdp  { "21064", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
48838889Sjdp  { "21064a", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
48938889Sjdp  { "21066", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
49038889Sjdp  { "21068", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
49138889Sjdp  { "21164", AXP_OPCODE_BASE|AXP_OPCODE_EV5 },
49238889Sjdp  { "21164a", AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX },
49338889Sjdp  { "21164pc", (AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX
49438889Sjdp		|AXP_OPCODE_MAX) },
49560484Sobrien  { "21264", (AXP_OPCODE_BASE|AXP_OPCODE_EV6|AXP_OPCODE_BWX
49660484Sobrien	      |AXP_OPCODE_MAX|AXP_OPCODE_CIX) },
497104834Sobrien  { "21264a", (AXP_OPCODE_BASE|AXP_OPCODE_EV6|AXP_OPCODE_BWX
498104834Sobrien	      |AXP_OPCODE_MAX|AXP_OPCODE_CIX) },
499104834Sobrien  { "21264b", (AXP_OPCODE_BASE|AXP_OPCODE_EV6|AXP_OPCODE_BWX
500104834Sobrien	      |AXP_OPCODE_MAX|AXP_OPCODE_CIX) },
50138889Sjdp
50238889Sjdp  { "ev4", AXP_OPCODE_BASE },
50338889Sjdp  { "ev45", AXP_OPCODE_BASE },
50438889Sjdp  { "lca45", AXP_OPCODE_BASE },
50538889Sjdp  { "ev5", AXP_OPCODE_BASE },
50638889Sjdp  { "ev56", AXP_OPCODE_BASE|AXP_OPCODE_BWX },
50738889Sjdp  { "pca56", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX },
50860484Sobrien  { "ev6", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX|AXP_OPCODE_CIX },
509104834Sobrien  { "ev67", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX|AXP_OPCODE_CIX },
510104834Sobrien  { "ev68", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX|AXP_OPCODE_CIX },
51138889Sjdp
51238889Sjdp  { "all", AXP_OPCODE_BASE },
51360484Sobrien  { 0, 0 }
51438889Sjdp};
51538889Sjdp
516218822Sdim/* Some instruction sets indexed by lg(size).  */
517218822Sdimstatic const char * const sextX_op[] = { "sextb", "sextw", "sextl", NULL };
518218822Sdimstatic const char * const insXl_op[] = { "insbl", "inswl", "insll", "insql" };
519218822Sdimstatic const char * const insXh_op[] = { NULL,    "inswh", "inslh", "insqh" };
520218822Sdimstatic const char * const extXl_op[] = { "extbl", "extwl", "extll", "extql" };
521218822Sdimstatic const char * const extXh_op[] = { NULL,    "extwh", "extlh", "extqh" };
522218822Sdimstatic const char * const mskXl_op[] = { "mskbl", "mskwl", "mskll", "mskql" };
523218822Sdimstatic const char * const mskXh_op[] = { NULL,    "mskwh", "msklh", "mskqh" };
524218822Sdimstatic const char * const stX_op[] = { "stb", "stw", "stl", "stq" };
525218822Sdimstatic const char * const ldXu_op[] = { "ldbu", "ldwu", NULL, NULL };
52633965Sjdp
527218822Sdimstatic void assemble_insn (const struct alpha_opcode *, const expressionS *, int, struct alpha_insn *, bfd_reloc_code_real_type);
528218822Sdimstatic void emit_insn (struct alpha_insn *);
529218822Sdimstatic void assemble_tokens (const char *, const expressionS *, int, int);
53033965Sjdp
53189857Sobrienstatic struct alpha_reloc_tag *
532218822Sdimget_alpha_reloc_tag (long sequence)
53389857Sobrien{
53489857Sobrien  char buffer[ALPHA_RELOC_DIGITS];
53589857Sobrien  struct alpha_reloc_tag *info;
53660484Sobrien
53789857Sobrien  sprintf (buffer, "!%ld", sequence);
53889857Sobrien
53989857Sobrien  info = (struct alpha_reloc_tag *) hash_find (alpha_literal_hash, buffer);
54089857Sobrien  if (! info)
54189857Sobrien    {
54289857Sobrien      size_t len = strlen (buffer);
54389857Sobrien      const char *errmsg;
54489857Sobrien
545218822Sdim      info = xcalloc (sizeof (struct alpha_reloc_tag) + len, 1);
54689857Sobrien
54789857Sobrien      info->segment = now_seg;
54889857Sobrien      info->sequence = sequence;
54989857Sobrien      strcpy (info->string, buffer);
550218822Sdim      errmsg = hash_insert (alpha_literal_hash, info->string, (void *) info);
55189857Sobrien      if (errmsg)
55289857Sobrien	as_fatal (errmsg);
55389857Sobrien    }
55489857Sobrien
55589857Sobrien  return info;
55689857Sobrien}
55789857Sobrien
55860484Sobrienstatic void
559218822Sdimalpha_adjust_relocs (bfd *abfd ATTRIBUTE_UNUSED,
560218822Sdim		     asection *sec,
561218822Sdim		     void * ptr ATTRIBUTE_UNUSED)
56260484Sobrien{
56360484Sobrien  segment_info_type *seginfo = seg_info (sec);
56460484Sobrien  fixS **prevP;
56560484Sobrien  fixS *fixp;
56660484Sobrien  fixS *next;
56789857Sobrien  fixS *slave;
56860484Sobrien
56977298Sobrien  /* If seginfo is NULL, we did not create this section; don't do
57077298Sobrien     anything with it.  By using a pointer to a pointer, we can update
57177298Sobrien     the links in place.  */
57260484Sobrien  if (seginfo == NULL)
57360484Sobrien    return;
57460484Sobrien
57560484Sobrien  /* If there are no relocations, skip the section.  */
57660484Sobrien  if (! seginfo->fix_root)
57760484Sobrien    return;
57860484Sobrien
579130561Sobrien  /* First rebuild the fixup chain without the explicit lituse and
58089857Sobrien     gpdisp_lo16 relocs.  */
58189857Sobrien  prevP = &seginfo->fix_root;
58260484Sobrien  for (fixp = seginfo->fix_root; fixp; fixp = next)
58360484Sobrien    {
58460484Sobrien      next = fixp->fx_next;
58577298Sobrien      fixp->fx_next = (fixS *) 0;
58660484Sobrien
58760484Sobrien      switch (fixp->fx_r_type)
58860484Sobrien	{
58989857Sobrien	case BFD_RELOC_ALPHA_LITUSE:
59089857Sobrien	  if (fixp->tc_fix_data.info->n_master == 0)
59189857Sobrien	    as_bad_where (fixp->fx_file, fixp->fx_line,
59289857Sobrien			  _("No !literal!%ld was found"),
59389857Sobrien			  fixp->tc_fix_data.info->sequence);
594130561Sobrien#ifdef RELOC_OP_P
595104834Sobrien	  if (fixp->fx_offset == LITUSE_ALPHA_TLSGD)
596104834Sobrien	    {
597104834Sobrien	      if (! fixp->tc_fix_data.info->saw_tlsgd)
598104834Sobrien		as_bad_where (fixp->fx_file, fixp->fx_line,
599104834Sobrien			      _("No !tlsgd!%ld was found"),
600104834Sobrien			      fixp->tc_fix_data.info->sequence);
601104834Sobrien	    }
602104834Sobrien	  else if (fixp->fx_offset == LITUSE_ALPHA_TLSLDM)
603104834Sobrien	    {
604104834Sobrien	      if (! fixp->tc_fix_data.info->saw_tlsldm)
605104834Sobrien		as_bad_where (fixp->fx_file, fixp->fx_line,
606104834Sobrien			      _("No !tlsldm!%ld was found"),
607104834Sobrien			      fixp->tc_fix_data.info->sequence);
608104834Sobrien	    }
609130561Sobrien#endif
61060484Sobrien	  break;
61160484Sobrien
61289857Sobrien	case BFD_RELOC_ALPHA_GPDISP_LO16:
61389857Sobrien	  if (fixp->tc_fix_data.info->n_master == 0)
61460484Sobrien	    as_bad_where (fixp->fx_file, fixp->fx_line,
61589857Sobrien			  _("No ldah !gpdisp!%ld was found"),
61660484Sobrien			  fixp->tc_fix_data.info->sequence);
61760484Sobrien	  break;
61889857Sobrien
619104834Sobrien	case BFD_RELOC_ALPHA_ELF_LITERAL:
620104834Sobrien	  if (fixp->tc_fix_data.info
621104834Sobrien	      && (fixp->tc_fix_data.info->saw_tlsgd
622104834Sobrien	          || fixp->tc_fix_data.info->saw_tlsldm))
623104834Sobrien	    break;
624104834Sobrien	  /* FALLTHRU */
625104834Sobrien
62689857Sobrien	default:
62789857Sobrien	  *prevP = fixp;
62889857Sobrien	  prevP = &fixp->fx_next;
62989857Sobrien	  break;
63060484Sobrien	}
63160484Sobrien    }
63260484Sobrien
633104834Sobrien  /* Go back and re-chain dependent relocations.  They are currently
634104834Sobrien     linked through the next_reloc field in reverse order, so as we
635104834Sobrien     go through the next_reloc chain, we effectively reverse the chain
636104834Sobrien     once again.
63789857Sobrien
63889857Sobrien     Except if there is more than one !literal for a given sequence
63989857Sobrien     number.  In that case, the programmer and/or compiler is not sure
64089857Sobrien     how control flows from literal to lituse, and we can't be sure to
64189857Sobrien     get the relaxation correct.
64289857Sobrien
64389857Sobrien     ??? Well, actually we could, if there are enough lituses such that
64489857Sobrien     we can make each literal have at least one of each lituse type
64589857Sobrien     present.  Not implemented.
64689857Sobrien
64789857Sobrien     Also suppress the optimization if the !literals/!lituses are spread
64889857Sobrien     in different segments.  This can happen with "intersting" uses of
64989857Sobrien     inline assembly; examples are present in the Linux kernel semaphores.  */
65089857Sobrien
65189857Sobrien  for (fixp = seginfo->fix_root; fixp; fixp = next)
65260484Sobrien    {
65389857Sobrien      next = fixp->fx_next;
65489857Sobrien      switch (fixp->fx_r_type)
65560484Sobrien	{
656104834Sobrien	case BFD_RELOC_ALPHA_TLSGD:
657104834Sobrien	case BFD_RELOC_ALPHA_TLSLDM:
658104834Sobrien	  if (!fixp->tc_fix_data.info)
659104834Sobrien	    break;
660104834Sobrien	  if (fixp->tc_fix_data.info->n_master == 0)
661104834Sobrien	    break;
662104834Sobrien	  else if (fixp->tc_fix_data.info->n_master > 1)
663104834Sobrien	    {
664104834Sobrien	      as_bad_where (fixp->fx_file, fixp->fx_line,
665104834Sobrien			    _("too many !literal!%ld for %s"),
666104834Sobrien			    fixp->tc_fix_data.info->sequence,
667104834Sobrien			    (fixp->fx_r_type == BFD_RELOC_ALPHA_TLSGD
668104834Sobrien			     ? "!tlsgd" : "!tlsldm"));
669104834Sobrien	      break;
670104834Sobrien	    }
671104834Sobrien
672104834Sobrien	  fixp->tc_fix_data.info->master->fx_next = fixp->fx_next;
673104834Sobrien	  fixp->fx_next = fixp->tc_fix_data.info->master;
674104834Sobrien	  fixp = fixp->fx_next;
675218822Sdim	  /* Fall through.  */
676104834Sobrien
67789857Sobrien	case BFD_RELOC_ALPHA_ELF_LITERAL:
678104834Sobrien	  if (fixp->tc_fix_data.info
679104834Sobrien	      && fixp->tc_fix_data.info->n_master == 1
68089857Sobrien	      && ! fixp->tc_fix_data.info->multi_section_p)
68160484Sobrien	    {
68289857Sobrien	      for (slave = fixp->tc_fix_data.info->slaves;
68389857Sobrien		   slave != (fixS *) 0;
68489857Sobrien		   slave = slave->tc_fix_data.next_reloc)
68560484Sobrien		{
68689857Sobrien		  slave->fx_next = fixp->fx_next;
68789857Sobrien		  fixp->fx_next = slave;
68860484Sobrien		}
68989857Sobrien	    }
69089857Sobrien	  break;
69160484Sobrien
69289857Sobrien	case BFD_RELOC_ALPHA_GPDISP_HI16:
69389857Sobrien	  if (fixp->tc_fix_data.info->n_slaves == 0)
69489857Sobrien	    as_bad_where (fixp->fx_file, fixp->fx_line,
69589857Sobrien			  _("No lda !gpdisp!%ld was found"),
69689857Sobrien			  fixp->tc_fix_data.info->sequence);
69789857Sobrien	  else
69889857Sobrien	    {
69989857Sobrien	      slave = fixp->tc_fix_data.info->slaves;
70089857Sobrien	      slave->fx_next = next;
70189857Sobrien	      fixp->fx_next = slave;
70260484Sobrien	    }
70389857Sobrien	  break;
70489857Sobrien
70589857Sobrien	default:
70689857Sobrien	  break;
70760484Sobrien	}
70860484Sobrien    }
70960484Sobrien}
710218822Sdim
711218822Sdim/* Before the relocations are written, reorder them, so that user
712218822Sdim   supplied !lituse relocations follow the appropriate !literal
713218822Sdim   relocations, and similarly for !gpdisp relocations.  */
714218822Sdim
715218822Sdimvoid
716218822Sdimalpha_before_fix (void)
717218822Sdim{
718218822Sdim  if (alpha_literal_hash)
719218822Sdim    bfd_map_over_sections (stdoutput, alpha_adjust_relocs, NULL);
720218822Sdim}
72160484Sobrien
72260484Sobrien#ifdef DEBUG_ALPHA
72360484Sobrienstatic void
724218822Sdimdebug_exp (expressionS tok[], int ntok)
72560484Sobrien{
72660484Sobrien  int i;
72760484Sobrien
72860484Sobrien  fprintf (stderr, "debug_exp: %d tokens", ntok);
72960484Sobrien  for (i = 0; i < ntok; i++)
73060484Sobrien    {
73160484Sobrien      expressionS *t = &tok[i];
73260484Sobrien      const char *name;
733130561Sobrien
73460484Sobrien      switch (t->X_op)
73560484Sobrien	{
73660484Sobrien	default:			name = "unknown";		break;
73760484Sobrien	case O_illegal:			name = "O_illegal";		break;
73860484Sobrien	case O_absent:			name = "O_absent";		break;
73960484Sobrien	case O_constant:		name = "O_constant";		break;
74060484Sobrien	case O_symbol:			name = "O_symbol";		break;
74160484Sobrien	case O_symbol_rva:		name = "O_symbol_rva";		break;
74260484Sobrien	case O_register:		name = "O_register";		break;
74360484Sobrien	case O_big:			name = "O_big";			break;
74460484Sobrien	case O_uminus:			name = "O_uminus";		break;
74560484Sobrien	case O_bit_not:			name = "O_bit_not";		break;
74660484Sobrien	case O_logical_not:		name = "O_logical_not";		break;
74760484Sobrien	case O_multiply:		name = "O_multiply";		break;
74860484Sobrien	case O_divide:			name = "O_divide";		break;
74960484Sobrien	case O_modulus:			name = "O_modulus";		break;
75060484Sobrien	case O_left_shift:		name = "O_left_shift";		break;
75160484Sobrien	case O_right_shift:		name = "O_right_shift";		break;
75260484Sobrien	case O_bit_inclusive_or:	name = "O_bit_inclusive_or";	break;
75360484Sobrien	case O_bit_or_not:		name = "O_bit_or_not";		break;
75460484Sobrien	case O_bit_exclusive_or:	name = "O_bit_exclusive_or";	break;
75560484Sobrien	case O_bit_and:			name = "O_bit_and";		break;
75660484Sobrien	case O_add:			name = "O_add";			break;
75760484Sobrien	case O_subtract:		name = "O_subtract";		break;
75860484Sobrien	case O_eq:			name = "O_eq";			break;
75960484Sobrien	case O_ne:			name = "O_ne";			break;
76060484Sobrien	case O_lt:			name = "O_lt";			break;
76160484Sobrien	case O_le:			name = "O_le";			break;
76260484Sobrien	case O_ge:			name = "O_ge";			break;
76360484Sobrien	case O_gt:			name = "O_gt";			break;
76460484Sobrien	case O_logical_and:		name = "O_logical_and";		break;
76560484Sobrien	case O_logical_or:		name = "O_logical_or";		break;
76660484Sobrien	case O_index:			name = "O_index";		break;
76760484Sobrien	case O_pregister:		name = "O_pregister";		break;
76860484Sobrien	case O_cpregister:		name = "O_cpregister";		break;
76960484Sobrien	case O_literal:			name = "O_literal";		break;
77091041Sobrien	case O_lituse_addr:		name = "O_lituse_addr";		break;
77160484Sobrien	case O_lituse_base:		name = "O_lituse_base";		break;
77260484Sobrien	case O_lituse_bytoff:		name = "O_lituse_bytoff";	break;
77360484Sobrien	case O_lituse_jsr:		name = "O_lituse_jsr";		break;
774104834Sobrien	case O_lituse_tlsgd:		name = "O_lituse_tlsgd";	break;
775104834Sobrien	case O_lituse_tlsldm:		name = "O_lituse_tlsldm";	break;
776218822Sdim	case O_lituse_jsrdirect:	name = "O_lituse_jsrdirect";	break;
77760484Sobrien	case O_gpdisp:			name = "O_gpdisp";		break;
77860484Sobrien	case O_gprelhigh:		name = "O_gprelhigh";		break;
77960484Sobrien	case O_gprellow:		name = "O_gprellow";		break;
78089857Sobrien	case O_gprel:			name = "O_gprel";		break;
78191041Sobrien	case O_samegp:			name = "O_samegp";		break;
782104834Sobrien	case O_tlsgd:			name = "O_tlsgd";		break;
783104834Sobrien	case O_tlsldm:			name = "O_tlsldm";		break;
784104834Sobrien	case O_gotdtprel:		name = "O_gotdtprel";		break;
785104834Sobrien	case O_dtprelhi:		name = "O_dtprelhi";		break;
786104834Sobrien	case O_dtprello:		name = "O_dtprello";		break;
787104834Sobrien	case O_dtprel:			name = "O_dtprel";		break;
788104834Sobrien	case O_gottprel:		name = "O_gottprel";		break;
789104834Sobrien	case O_tprelhi:			name = "O_tprelhi";		break;
790104834Sobrien	case O_tprello:			name = "O_tprello";		break;
791104834Sobrien	case O_tprel:			name = "O_tprel";		break;
79260484Sobrien	}
79360484Sobrien
79460484Sobrien      fprintf (stderr, ", %s(%s, %s, %d)", name,
79560484Sobrien	       (t->X_add_symbol) ? S_GET_NAME (t->X_add_symbol) : "--",
79660484Sobrien	       (t->X_op_symbol) ? S_GET_NAME (t->X_op_symbol) : "--",
79777298Sobrien	       (int) t->X_add_number);
79860484Sobrien    }
79960484Sobrien  fprintf (stderr, "\n");
80060484Sobrien  fflush (stderr);
80160484Sobrien}
80260484Sobrien#endif
80360484Sobrien
80433965Sjdp/* Parse the arguments to an opcode.  */
80533965Sjdp
80633965Sjdpstatic int
807218822Sdimtokenize_arguments (char *str,
808218822Sdim		    expressionS tok[],
809218822Sdim		    int ntok)
81033965Sjdp{
81133965Sjdp  expressionS *end_tok = tok + ntok;
81233965Sjdp  char *old_input_line_pointer;
81333965Sjdp  int saw_comma = 0, saw_arg = 0;
81460484Sobrien#ifdef DEBUG_ALPHA
81560484Sobrien  expressionS *orig_tok = tok;
81660484Sobrien#endif
817130561Sobrien#ifdef RELOC_OP_P
81860484Sobrien  char *p;
81960484Sobrien  const struct alpha_reloc_op_tag *r;
82060484Sobrien  int c, i;
82160484Sobrien  size_t len;
82260484Sobrien  int reloc_found_p = 0;
823130561Sobrien#endif
82433965Sjdp
82533965Sjdp  memset (tok, 0, sizeof (*tok) * ntok);
82633965Sjdp
827130561Sobrien  /* Save and restore input_line_pointer around this function.  */
82833965Sjdp  old_input_line_pointer = input_line_pointer;
82933965Sjdp  input_line_pointer = str;
83033965Sjdp
83189857Sobrien#ifdef RELOC_OP_P
83289857Sobrien  /* ??? Wrest control of ! away from the regular expression parser.  */
83389857Sobrien  is_end_of_line[(unsigned char) '!'] = 1;
83489857Sobrien#endif
83589857Sobrien
83633965Sjdp  while (tok < end_tok && *input_line_pointer)
83733965Sjdp    {
83833965Sjdp      SKIP_WHITESPACE ();
83933965Sjdp      switch (*input_line_pointer)
84033965Sjdp	{
84133965Sjdp	case '\0':
84233965Sjdp	  goto fini;
84333965Sjdp
84460484Sobrien#ifdef RELOC_OP_P
84560484Sobrien	case '!':
84660484Sobrien	  /* A relocation operand can be placed after the normal operand on an
84760484Sobrien	     assembly language statement, and has the following form:
84860484Sobrien		!relocation_type!sequence_number.  */
84960484Sobrien	  if (reloc_found_p)
850130561Sobrien	    {
851130561Sobrien	      /* Only support one relocation op per insn.  */
85260484Sobrien	      as_bad (_("More than one relocation op per insn"));
85360484Sobrien	      goto err_report;
85460484Sobrien	    }
85560484Sobrien
85660484Sobrien	  if (!saw_arg)
85760484Sobrien	    goto err;
85860484Sobrien
85989857Sobrien	  ++input_line_pointer;
860104834Sobrien	  SKIP_WHITESPACE ();
86189857Sobrien	  p = input_line_pointer;
86289857Sobrien	  c = get_symbol_end ();
86360484Sobrien
864130561Sobrien	  /* Parse !relocation_type.  */
86589857Sobrien	  len = input_line_pointer - p;
86660484Sobrien	  if (len == 0)
86760484Sobrien	    {
86860484Sobrien	      as_bad (_("No relocation operand"));
86960484Sobrien	      goto err_report;
87060484Sobrien	    }
87160484Sobrien
87289857Sobrien	  r = &alpha_reloc_op[0];
87389857Sobrien	  for (i = alpha_num_reloc_op - 1; i >= 0; i--, r++)
87489857Sobrien	    if (len == r->length && memcmp (p, r->name, len) == 0)
87589857Sobrien	      break;
87689857Sobrien	  if (i < 0)
87760484Sobrien	    {
87889857Sobrien	      as_bad (_("Unknown relocation operand: !%s"), p);
87960484Sobrien	      goto err_report;
88060484Sobrien	    }
88160484Sobrien
88289857Sobrien	  *input_line_pointer = c;
883104834Sobrien	  SKIP_WHITESPACE ();
88489857Sobrien	  if (*input_line_pointer != '!')
88560484Sobrien	    {
88689857Sobrien	      if (r->require_seq)
88789857Sobrien		{
88889857Sobrien		  as_bad (_("no sequence number after !%s"), p);
88989857Sobrien		  goto err_report;
89089857Sobrien		}
89189857Sobrien
89289857Sobrien	      tok->X_add_number = 0;
89360484Sobrien	    }
89489857Sobrien	  else
89560484Sobrien	    {
89689857Sobrien	      if (! r->allow_seq)
89789857Sobrien		{
89889857Sobrien		  as_bad (_("!%s does not use a sequence number"), p);
89989857Sobrien		  goto err_report;
90089857Sobrien		}
90160484Sobrien
90289857Sobrien	      input_line_pointer++;
90360484Sobrien
904130561Sobrien	      /* Parse !sequence_number.  */
90589857Sobrien	      expression (tok);
90689857Sobrien	      if (tok->X_op != O_constant || tok->X_add_number <= 0)
90789857Sobrien		{
90889857Sobrien		  as_bad (_("Bad sequence number: !%s!%s"),
90989857Sobrien			  r->name, input_line_pointer);
91089857Sobrien		  goto err_report;
91189857Sobrien		}
91260484Sobrien	    }
91360484Sobrien
91460484Sobrien	  tok->X_op = r->op;
91560484Sobrien	  reloc_found_p = 1;
91660484Sobrien	  ++tok;
91760484Sobrien	  break;
91889857Sobrien#endif /* RELOC_OP_P */
91960484Sobrien
92033965Sjdp	case ',':
92133965Sjdp	  ++input_line_pointer;
92233965Sjdp	  if (saw_comma || !saw_arg)
92333965Sjdp	    goto err;
92433965Sjdp	  saw_comma = 1;
92533965Sjdp	  break;
92633965Sjdp
92733965Sjdp	case '(':
92833965Sjdp	  {
92933965Sjdp	    char *hold = input_line_pointer++;
93033965Sjdp
93177298Sobrien	    /* First try for parenthesized register ...  */
93233965Sjdp	    expression (tok);
93333965Sjdp	    if (*input_line_pointer == ')' && tok->X_op == O_register)
93433965Sjdp	      {
93533965Sjdp		tok->X_op = (saw_comma ? O_cpregister : O_pregister);
93633965Sjdp		saw_comma = 0;
93733965Sjdp		saw_arg = 1;
93833965Sjdp		++input_line_pointer;
93933965Sjdp		++tok;
94033965Sjdp		break;
94133965Sjdp	      }
94233965Sjdp
943130561Sobrien	    /* ... then fall through to plain expression.  */
94433965Sjdp	    input_line_pointer = hold;
94533965Sjdp	  }
94633965Sjdp
94733965Sjdp	default:
94833965Sjdp	  if (saw_arg && !saw_comma)
94933965Sjdp	    goto err;
95060484Sobrien
95133965Sjdp	  expression (tok);
95233965Sjdp	  if (tok->X_op == O_illegal || tok->X_op == O_absent)
95333965Sjdp	    goto err;
95433965Sjdp
95533965Sjdp	  saw_comma = 0;
95633965Sjdp	  saw_arg = 1;
95733965Sjdp	  ++tok;
95833965Sjdp	  break;
95933965Sjdp	}
96033965Sjdp    }
96133965Sjdp
96233965Sjdpfini:
96333965Sjdp  if (saw_comma)
96433965Sjdp    goto err;
96533965Sjdp  input_line_pointer = old_input_line_pointer;
96660484Sobrien
96760484Sobrien#ifdef DEBUG_ALPHA
96860484Sobrien  debug_exp (orig_tok, ntok - (end_tok - tok));
96960484Sobrien#endif
97089857Sobrien#ifdef RELOC_OP_P
97189857Sobrien  is_end_of_line[(unsigned char) '!'] = 0;
97289857Sobrien#endif
97360484Sobrien
97433965Sjdp  return ntok - (end_tok - tok);
97533965Sjdp
97633965Sjdperr:
97789857Sobrien#ifdef RELOC_OP_P
97889857Sobrien  is_end_of_line[(unsigned char) '!'] = 0;
97989857Sobrien#endif
98033965Sjdp  input_line_pointer = old_input_line_pointer;
98160484Sobrien  return TOKENIZE_ERROR;
98260484Sobrien
983130561Sobrien#ifdef RELOC_OP_P
98489857Sobrienerr_report:
98589857Sobrien  is_end_of_line[(unsigned char) '!'] = 0;
98689857Sobrien#endif
98760484Sobrien  input_line_pointer = old_input_line_pointer;
98860484Sobrien  return TOKENIZE_ERROR_REPORT;
98933965Sjdp}
99033965Sjdp
99133965Sjdp/* Search forward through all variants of an opcode looking for a
99233965Sjdp   syntax match.  */
99333965Sjdp
99433965Sjdpstatic const struct alpha_opcode *
995218822Sdimfind_opcode_match (const struct alpha_opcode *first_opcode,
996218822Sdim		   const expressionS *tok,
997218822Sdim		   int *pntok,
998218822Sdim		   int *pcpumatch)
99933965Sjdp{
100033965Sjdp  const struct alpha_opcode *opcode = first_opcode;
100133965Sjdp  int ntok = *pntok;
100233965Sjdp  int got_cpu_match = 0;
100333965Sjdp
100433965Sjdp  do
100533965Sjdp    {
100633965Sjdp      const unsigned char *opidx;
100733965Sjdp      int tokidx = 0;
100833965Sjdp
1009130561Sobrien      /* Don't match opcodes that don't exist on this architecture.  */
101033965Sjdp      if (!(opcode->flags & alpha_target))
101133965Sjdp	goto match_failed;
101233965Sjdp
101333965Sjdp      got_cpu_match = 1;
101433965Sjdp
101533965Sjdp      for (opidx = opcode->operands; *opidx; ++opidx)
101633965Sjdp	{
101733965Sjdp	  const struct alpha_operand *operand = &alpha_operands[*opidx];
101833965Sjdp
1019130561Sobrien	  /* Only take input from real operands.  */
102033965Sjdp	  if (operand->flags & AXP_OPERAND_FAKE)
102133965Sjdp	    continue;
102233965Sjdp
1023130561Sobrien	  /* When we expect input, make sure we have it.  */
102433965Sjdp	  if (tokidx >= ntok)
102533965Sjdp	    {
102633965Sjdp	      if ((operand->flags & AXP_OPERAND_OPTIONAL_MASK) == 0)
102733965Sjdp		goto match_failed;
102833965Sjdp	      continue;
102933965Sjdp	    }
103033965Sjdp
1031130561Sobrien	  /* Match operand type with expression type.  */
103233965Sjdp	  switch (operand->flags & AXP_OPERAND_TYPECHECK_MASK)
103333965Sjdp	    {
103433965Sjdp	    case AXP_OPERAND_IR:
103533965Sjdp	      if (tok[tokidx].X_op != O_register
103677298Sobrien		  || !is_ir_num (tok[tokidx].X_add_number))
103733965Sjdp		goto match_failed;
103833965Sjdp	      break;
103933965Sjdp	    case AXP_OPERAND_FPR:
104033965Sjdp	      if (tok[tokidx].X_op != O_register
104177298Sobrien		  || !is_fpr_num (tok[tokidx].X_add_number))
104233965Sjdp		goto match_failed;
104333965Sjdp	      break;
104477298Sobrien	    case AXP_OPERAND_IR | AXP_OPERAND_PARENS:
104533965Sjdp	      if (tok[tokidx].X_op != O_pregister
104677298Sobrien		  || !is_ir_num (tok[tokidx].X_add_number))
104733965Sjdp		goto match_failed;
104833965Sjdp	      break;
104977298Sobrien	    case AXP_OPERAND_IR | AXP_OPERAND_PARENS | AXP_OPERAND_COMMA:
105033965Sjdp	      if (tok[tokidx].X_op != O_cpregister
105177298Sobrien		  || !is_ir_num (tok[tokidx].X_add_number))
105233965Sjdp		goto match_failed;
105333965Sjdp	      break;
105433965Sjdp
105533965Sjdp	    case AXP_OPERAND_RELATIVE:
105633965Sjdp	    case AXP_OPERAND_SIGNED:
105733965Sjdp	    case AXP_OPERAND_UNSIGNED:
105833965Sjdp	      switch (tok[tokidx].X_op)
105933965Sjdp		{
106033965Sjdp		case O_illegal:
106133965Sjdp		case O_absent:
106233965Sjdp		case O_register:
106333965Sjdp		case O_pregister:
106433965Sjdp		case O_cpregister:
106533965Sjdp		  goto match_failed;
106660484Sobrien
106760484Sobrien		default:
106860484Sobrien		  break;
106933965Sjdp		}
107033965Sjdp	      break;
107133965Sjdp
107233965Sjdp	    default:
1073130561Sobrien	      /* Everything else should have been fake.  */
107477298Sobrien	      abort ();
107533965Sjdp	    }
107633965Sjdp	  ++tokidx;
107733965Sjdp	}
107833965Sjdp
1079130561Sobrien      /* Possible match -- did we use all of our input?  */
108033965Sjdp      if (tokidx == ntok)
108133965Sjdp	{
108233965Sjdp	  *pntok = ntok;
108333965Sjdp	  return opcode;
108433965Sjdp	}
108533965Sjdp
108633965Sjdp    match_failed:;
108733965Sjdp    }
1088130561Sobrien  while (++opcode - alpha_opcodes < (int) alpha_num_opcodes
108977298Sobrien	 && !strcmp (opcode->name, first_opcode->name));
109033965Sjdp
109133965Sjdp  if (*pcpumatch)
109277298Sobrien    *pcpumatch = got_cpu_match;
109333965Sjdp
109433965Sjdp  return NULL;
109533965Sjdp}
109633965Sjdp
109733965Sjdp/* Given an opcode name and a pre-tokenized set of arguments, assemble
109833965Sjdp   the insn, but do not emit it.
109933965Sjdp
110033965Sjdp   Note that this implies no macros allowed, since we can't store more
110133965Sjdp   than one insn in an insn structure.  */
110233965Sjdp
110333965Sjdpstatic void
1104218822Sdimassemble_tokens_to_insn (const char *opname,
1105218822Sdim			 const expressionS *tok,
1106218822Sdim			 int ntok,
1107218822Sdim			 struct alpha_insn *insn)
110833965Sjdp{
110933965Sjdp  const struct alpha_opcode *opcode;
111033965Sjdp
1111218822Sdim  /* Search opcodes.  */
111233965Sjdp  opcode = (const struct alpha_opcode *) hash_find (alpha_opcode_hash, opname);
111333965Sjdp  if (opcode)
111433965Sjdp    {
111533965Sjdp      int cpumatch;
111633965Sjdp      opcode = find_opcode_match (opcode, tok, &ntok, &cpumatch);
111733965Sjdp      if (opcode)
111833965Sjdp	{
111989857Sobrien	  assemble_insn (opcode, tok, ntok, insn, BFD_RELOC_UNUSED);
112033965Sjdp	  return;
112133965Sjdp	}
112233965Sjdp      else if (cpumatch)
112360484Sobrien	as_bad (_("inappropriate arguments for opcode `%s'"), opname);
112433965Sjdp      else
112560484Sobrien	as_bad (_("opcode `%s' not supported for target %s"), opname,
112677298Sobrien		alpha_target_name);
112733965Sjdp    }
112833965Sjdp  else
112960484Sobrien    as_bad (_("unknown opcode `%s'"), opname);
113033965Sjdp}
113133965Sjdp
1132218822Sdim/* Build a BFD section with its flags set appropriately for the .lita,
1133218822Sdim   .lit8, or .lit4 sections.  */
113433965Sjdp
113533965Sjdpstatic void
1136218822Sdimcreate_literal_section (const char *name,
1137218822Sdim			segT *secp,
1138218822Sdim			symbolS **symp)
113933965Sjdp{
114033965Sjdp  segT current_section = now_seg;
114133965Sjdp  int current_subsec = now_subseg;
1142218822Sdim  segT new_sec;
114333965Sjdp
1144218822Sdim  *secp = new_sec = subseg_new (name, 0);
1145218822Sdim  subseg_set (current_section, current_subsec);
1146218822Sdim  bfd_set_section_alignment (stdoutput, new_sec, 4);
1147218822Sdim  bfd_set_section_flags (stdoutput, new_sec,
1148218822Sdim			 SEC_RELOC | SEC_ALLOC | SEC_LOAD | SEC_READONLY
1149218822Sdim			 | SEC_DATA);
115033965Sjdp
1151218822Sdim  S_CLEAR_EXTERNAL (*symp = section_symbol (new_sec));
115233965Sjdp}
115333965Sjdp
115433965Sjdp/* Load a (partial) expression into a target register.
115533965Sjdp
115633965Sjdp   If poffset is not null, after the call it will either contain
115733965Sjdp   O_constant 0, or a 16-bit offset appropriate for any MEM format
115833965Sjdp   instruction.  In addition, pbasereg will be modified to point to
115933965Sjdp   the base register to use in that MEM format instruction.
116033965Sjdp
116133965Sjdp   In any case, *pbasereg should contain a base register to add to the
116233965Sjdp   expression.  This will normally be either AXP_REG_ZERO or
116333965Sjdp   alpha_gp_register.  Symbol addresses will always be loaded via $gp,
116433965Sjdp   so "foo($0)" is interpreted as adding the address of foo to $0;
116533965Sjdp   i.e. "ldq $targ, LIT($gp); addq $targ, $0, $targ".  Odd, perhaps,
116633965Sjdp   but this is what OSF/1 does.
116733965Sjdp
116860484Sobrien   If explicit relocations of the form !literal!<number> are allowed,
1169130561Sobrien   and used, then explicit_reloc with be an expression pointer.
117060484Sobrien
117189857Sobrien   Finally, the return value is nonzero if the calling macro may emit
117289857Sobrien   a LITUSE reloc if otherwise appropriate; the return value is the
117389857Sobrien   sequence number to use.  */
117433965Sjdp
117589857Sobrienstatic long
1176218822Sdimload_expression (int targreg,
1177218822Sdim		 const expressionS *exp,
1178218822Sdim		 int *pbasereg,
1179218822Sdim		 expressionS *poffset)
118033965Sjdp{
118189857Sobrien  long emit_lituse = 0;
118233965Sjdp  offsetT addend = exp->X_add_number;
118333965Sjdp  int basereg = *pbasereg;
118433965Sjdp  struct alpha_insn insn;
118533965Sjdp  expressionS newtok[3];
118633965Sjdp
118733965Sjdp  switch (exp->X_op)
118833965Sjdp    {
118933965Sjdp    case O_symbol:
119033965Sjdp      {
119133965Sjdp#ifdef OBJ_ECOFF
119233965Sjdp	offsetT lit;
119333965Sjdp
1194130561Sobrien	/* Attempt to reduce .lit load by splitting the offset from
119533965Sjdp	   its symbol when possible, but don't create a situation in
119633965Sjdp	   which we'd fail.  */
119733965Sjdp	if (!range_signed_32 (addend) &&
119833965Sjdp	    (alpha_noat_on || targreg == AXP_REG_AT))
119933965Sjdp	  {
120033965Sjdp	    lit = add_to_literal_pool (exp->X_add_symbol, addend,
120133965Sjdp				       alpha_lita_section, 8);
120233965Sjdp	    addend = 0;
120333965Sjdp	  }
120433965Sjdp	else
1205218822Sdim	  lit = add_to_literal_pool (exp->X_add_symbol, 0,
1206218822Sdim				     alpha_lita_section, 8);
120733965Sjdp
120833965Sjdp	if (lit >= 0x8000)
120960484Sobrien	  as_fatal (_("overflow in literal (.lita) table"));
121033965Sjdp
1211218822Sdim	/* Emit "ldq r, lit(gp)".  */
121233965Sjdp
121333965Sjdp	if (basereg != alpha_gp_register && targreg == basereg)
121433965Sjdp	  {
121533965Sjdp	    if (alpha_noat_on)
121660484Sobrien	      as_bad (_("macro requires $at register while noat in effect"));
121733965Sjdp	    if (targreg == AXP_REG_AT)
121860484Sobrien	      as_bad (_("macro requires $at while $at in use"));
121933965Sjdp
122033965Sjdp	    set_tok_reg (newtok[0], AXP_REG_AT);
122133965Sjdp	  }
122233965Sjdp	else
122333965Sjdp	  set_tok_reg (newtok[0], targreg);
1224218822Sdim
122533965Sjdp	set_tok_sym (newtok[1], alpha_lita_symbol, lit);
122633965Sjdp	set_tok_preg (newtok[2], alpha_gp_register);
122733965Sjdp
122833965Sjdp	assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
122933965Sjdp
123033965Sjdp	assert (insn.nfixups == 1);
123133965Sjdp	insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL;
123289857Sobrien	insn.sequence = emit_lituse = next_sequence_num--;
123333965Sjdp#endif /* OBJ_ECOFF */
123433965Sjdp#ifdef OBJ_ELF
1235218822Sdim	/* Emit "ldq r, gotoff(gp)".  */
123633965Sjdp
123733965Sjdp	if (basereg != alpha_gp_register && targreg == basereg)
123833965Sjdp	  {
123933965Sjdp	    if (alpha_noat_on)
124060484Sobrien	      as_bad (_("macro requires $at register while noat in effect"));
124133965Sjdp	    if (targreg == AXP_REG_AT)
124260484Sobrien	      as_bad (_("macro requires $at while $at in use"));
124333965Sjdp
124433965Sjdp	    set_tok_reg (newtok[0], AXP_REG_AT);
124533965Sjdp	  }
124633965Sjdp	else
124733965Sjdp	  set_tok_reg (newtok[0], targreg);
124833965Sjdp
124938889Sjdp	/* XXX: Disable this .got minimizing optimization so that we can get
125038889Sjdp	   better instruction offset knowledge in the compiler.  This happens
125138889Sjdp	   very infrequently anyway.  */
125277298Sobrien	if (1
125377298Sobrien	    || (!range_signed_32 (addend)
125477298Sobrien		&& (alpha_noat_on || targreg == AXP_REG_AT)))
125533965Sjdp	  {
125633965Sjdp	    newtok[1] = *exp;
125733965Sjdp	    addend = 0;
125833965Sjdp	  }
125933965Sjdp	else
1260218822Sdim	  set_tok_sym (newtok[1], exp->X_add_symbol, 0);
126133965Sjdp
126233965Sjdp	set_tok_preg (newtok[2], alpha_gp_register);
126333965Sjdp
126433965Sjdp	assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
126533965Sjdp
126633965Sjdp	assert (insn.nfixups == 1);
126789857Sobrien	insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL;
126889857Sobrien	insn.sequence = emit_lituse = next_sequence_num--;
126933965Sjdp#endif /* OBJ_ELF */
127033965Sjdp#ifdef OBJ_EVAX
127133965Sjdp	offsetT link;
127233965Sjdp
127333965Sjdp	/* Find symbol or symbol pointer in link section.  */
127433965Sjdp
127533965Sjdp	if (exp->X_add_symbol == alpha_evax_proc.symbol)
127633965Sjdp	  {
127733965Sjdp	    if (range_signed_16 (addend))
127833965Sjdp	      {
127933965Sjdp		set_tok_reg (newtok[0], targreg);
128033965Sjdp		set_tok_const (newtok[1], addend);
128133965Sjdp		set_tok_preg (newtok[2], basereg);
128233965Sjdp		assemble_tokens_to_insn ("lda", newtok, 3, &insn);
128333965Sjdp		addend = 0;
128433965Sjdp	      }
128533965Sjdp	    else
128633965Sjdp	      {
128733965Sjdp		set_tok_reg (newtok[0], targreg);
128833965Sjdp		set_tok_const (newtok[1], 0);
128933965Sjdp		set_tok_preg (newtok[2], basereg);
129033965Sjdp		assemble_tokens_to_insn ("lda", newtok, 3, &insn);
129133965Sjdp	      }
129233965Sjdp	  }
129333965Sjdp	else
129433965Sjdp	  {
129533965Sjdp	    if (!range_signed_32 (addend))
129633965Sjdp	      {
129733965Sjdp		link = add_to_link_pool (alpha_evax_proc.symbol,
129833965Sjdp					 exp->X_add_symbol, addend);
129933965Sjdp		addend = 0;
130033965Sjdp	      }
130133965Sjdp	    else
1302218822Sdim	      link = add_to_link_pool (alpha_evax_proc.symbol,
1303218822Sdim				       exp->X_add_symbol, 0);
1304218822Sdim
130533965Sjdp	    set_tok_reg (newtok[0], targreg);
130633965Sjdp	    set_tok_const (newtok[1], link);
130733965Sjdp	    set_tok_preg (newtok[2], basereg);
130833965Sjdp	    assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
130933965Sjdp	  }
131033965Sjdp#endif /* OBJ_EVAX */
131133965Sjdp
131277298Sobrien	emit_insn (&insn);
131333965Sjdp
131433965Sjdp#ifndef OBJ_EVAX
131533965Sjdp	if (basereg != alpha_gp_register && basereg != AXP_REG_ZERO)
131633965Sjdp	  {
1317218822Sdim	    /* Emit "addq r, base, r".  */
131833965Sjdp
131933965Sjdp	    set_tok_reg (newtok[1], basereg);
132033965Sjdp	    set_tok_reg (newtok[2], targreg);
132133965Sjdp	    assemble_tokens ("addq", newtok, 3, 0);
132233965Sjdp	  }
132333965Sjdp#endif
132433965Sjdp	basereg = targreg;
132533965Sjdp      }
132633965Sjdp      break;
132733965Sjdp
132833965Sjdp    case O_constant:
132933965Sjdp      break;
133033965Sjdp
133133965Sjdp    case O_subtract:
133233965Sjdp      /* Assume that this difference expression will be resolved to an
133377298Sobrien	 absolute value and that that value will fit in 16 bits.  */
133433965Sjdp
133533965Sjdp      set_tok_reg (newtok[0], targreg);
133633965Sjdp      newtok[1] = *exp;
133733965Sjdp      set_tok_preg (newtok[2], basereg);
133833965Sjdp      assemble_tokens ("lda", newtok, 3, 0);
133933965Sjdp
134033965Sjdp      if (poffset)
134133965Sjdp	set_tok_const (*poffset, 0);
134233965Sjdp      return 0;
134333965Sjdp
134438889Sjdp    case O_big:
134560484Sobrien      if (exp->X_add_number > 0)
134660484Sobrien	as_bad (_("bignum invalid; zero assumed"));
134760484Sobrien      else
134860484Sobrien	as_bad (_("floating point number invalid; zero assumed"));
134938889Sjdp      addend = 0;
135038889Sjdp      break;
135138889Sjdp
135233965Sjdp    default:
135360484Sobrien      as_bad (_("can't handle expression"));
135460484Sobrien      addend = 0;
135560484Sobrien      break;
135633965Sjdp    }
135733965Sjdp
135833965Sjdp  if (!range_signed_32 (addend))
135933965Sjdp    {
136033965Sjdp      offsetT lit;
136189857Sobrien      long seq_num = next_sequence_num--;
136233965Sjdp
136389857Sobrien      /* For 64-bit addends, just put it in the literal pool.  */
136433965Sjdp#ifdef OBJ_EVAX
1365218822Sdim      /* Emit "ldq targreg, lit(basereg)".  */
136633965Sjdp      lit = add_to_link_pool (alpha_evax_proc.symbol,
136733965Sjdp			      section_symbol (absolute_section), addend);
136833965Sjdp      set_tok_reg (newtok[0], targreg);
136933965Sjdp      set_tok_const (newtok[1], lit);
137033965Sjdp      set_tok_preg (newtok[2], alpha_gp_register);
137133965Sjdp      assemble_tokens ("ldq", newtok, 3, 0);
137233965Sjdp#else
137333965Sjdp
137433965Sjdp      if (alpha_lit8_section == NULL)
137533965Sjdp	{
137633965Sjdp	  create_literal_section (".lit8",
137733965Sjdp				  &alpha_lit8_section,
137833965Sjdp				  &alpha_lit8_symbol);
137933965Sjdp
138033965Sjdp#ifdef OBJ_ECOFF
138133965Sjdp	  alpha_lit8_literal = add_to_literal_pool (alpha_lit8_symbol, 0x8000,
138233965Sjdp						    alpha_lita_section, 8);
138333965Sjdp	  if (alpha_lit8_literal >= 0x8000)
138460484Sobrien	    as_fatal (_("overflow in literal (.lita) table"));
138533965Sjdp#endif
138633965Sjdp	}
138733965Sjdp
138833965Sjdp      lit = add_to_literal_pool (NULL, addend, alpha_lit8_section, 8) - 0x8000;
138933965Sjdp      if (lit >= 0x8000)
139060484Sobrien	as_fatal (_("overflow in literal (.lit8) table"));
139133965Sjdp
1392218822Sdim      /* Emit "lda litreg, .lit8+0x8000".  */
139333965Sjdp
139433965Sjdp      if (targreg == basereg)
139533965Sjdp	{
139633965Sjdp	  if (alpha_noat_on)
139760484Sobrien	    as_bad (_("macro requires $at register while noat in effect"));
139833965Sjdp	  if (targreg == AXP_REG_AT)
139960484Sobrien	    as_bad (_("macro requires $at while $at in use"));
140033965Sjdp
140133965Sjdp	  set_tok_reg (newtok[0], AXP_REG_AT);
140233965Sjdp	}
140333965Sjdp      else
140433965Sjdp	set_tok_reg (newtok[0], targreg);
140533965Sjdp#ifdef OBJ_ECOFF
140633965Sjdp      set_tok_sym (newtok[1], alpha_lita_symbol, alpha_lit8_literal);
140733965Sjdp#endif
140833965Sjdp#ifdef OBJ_ELF
140933965Sjdp      set_tok_sym (newtok[1], alpha_lit8_symbol, 0x8000);
141033965Sjdp#endif
141133965Sjdp      set_tok_preg (newtok[2], alpha_gp_register);
141233965Sjdp
141333965Sjdp      assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
141433965Sjdp
141533965Sjdp      assert (insn.nfixups == 1);
141633965Sjdp#ifdef OBJ_ECOFF
141733965Sjdp      insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL;
141833965Sjdp#endif
141933965Sjdp#ifdef OBJ_ELF
142033965Sjdp      insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL;
142133965Sjdp#endif
142289857Sobrien      insn.sequence = seq_num;
142333965Sjdp
142433965Sjdp      emit_insn (&insn);
142533965Sjdp
1426218822Sdim      /* Emit "ldq litreg, lit(litreg)".  */
142733965Sjdp
142833965Sjdp      set_tok_const (newtok[1], lit);
142933965Sjdp      set_tok_preg (newtok[2], newtok[0].X_add_number);
143033965Sjdp
143133965Sjdp      assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
143233965Sjdp
143333965Sjdp      assert (insn.nfixups < MAX_INSN_FIXUPS);
143489857Sobrien      insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
143589857Sobrien      insn.fixups[insn.nfixups].exp.X_op = O_absent;
143633965Sjdp      insn.nfixups++;
143789857Sobrien      insn.sequence = seq_num;
143833965Sjdp      emit_lituse = 0;
143933965Sjdp
144033965Sjdp      emit_insn (&insn);
144133965Sjdp
1442218822Sdim      /* Emit "addq litreg, base, target".  */
144333965Sjdp
144433965Sjdp      if (basereg != AXP_REG_ZERO)
144533965Sjdp	{
144633965Sjdp	  set_tok_reg (newtok[1], basereg);
144733965Sjdp	  set_tok_reg (newtok[2], targreg);
144833965Sjdp	  assemble_tokens ("addq", newtok, 3, 0);
144933965Sjdp	}
145033965Sjdp#endif /* !OBJ_EVAX */
145133965Sjdp
145233965Sjdp      if (poffset)
145333965Sjdp	set_tok_const (*poffset, 0);
145433965Sjdp      *pbasereg = targreg;
145533965Sjdp    }
145633965Sjdp  else
145733965Sjdp    {
145833965Sjdp      offsetT low, high, extra, tmp;
145933965Sjdp
1460218822Sdim      /* For 32-bit operands, break up the addend.  */
146133965Sjdp
146233965Sjdp      low = sign_extend_16 (addend);
146333965Sjdp      tmp = addend - low;
146433965Sjdp      high = sign_extend_16 (tmp >> 16);
146533965Sjdp
146633965Sjdp      if (tmp - (high << 16))
146733965Sjdp	{
146833965Sjdp	  extra = 0x4000;
146933965Sjdp	  tmp -= 0x40000000;
147033965Sjdp	  high = sign_extend_16 (tmp >> 16);
147133965Sjdp	}
147233965Sjdp      else
147333965Sjdp	extra = 0;
147433965Sjdp
147533965Sjdp      set_tok_reg (newtok[0], targreg);
147633965Sjdp      set_tok_preg (newtok[2], basereg);
147733965Sjdp
147833965Sjdp      if (extra)
147933965Sjdp	{
1480218822Sdim	  /* Emit "ldah r, extra(r).  */
148133965Sjdp	  set_tok_const (newtok[1], extra);
148233965Sjdp	  assemble_tokens ("ldah", newtok, 3, 0);
148333965Sjdp	  set_tok_preg (newtok[2], basereg = targreg);
148433965Sjdp	}
148533965Sjdp
148633965Sjdp      if (high)
148733965Sjdp	{
1488218822Sdim	  /* Emit "ldah r, high(r).  */
148933965Sjdp	  set_tok_const (newtok[1], high);
149033965Sjdp	  assemble_tokens ("ldah", newtok, 3, 0);
149133965Sjdp	  basereg = targreg;
149233965Sjdp	  set_tok_preg (newtok[2], basereg);
149333965Sjdp	}
149433965Sjdp
149533965Sjdp      if ((low && !poffset) || (!poffset && basereg != targreg))
149633965Sjdp	{
1497218822Sdim	  /* Emit "lda r, low(base)".  */
149833965Sjdp	  set_tok_const (newtok[1], low);
149933965Sjdp	  assemble_tokens ("lda", newtok, 3, 0);
150033965Sjdp	  basereg = targreg;
150133965Sjdp	  low = 0;
150233965Sjdp	}
150333965Sjdp
150433965Sjdp      if (poffset)
150533965Sjdp	set_tok_const (*poffset, low);
150633965Sjdp      *pbasereg = basereg;
150733965Sjdp    }
150833965Sjdp
150933965Sjdp  return emit_lituse;
151033965Sjdp}
151133965Sjdp
151233965Sjdp/* The lda macro differs from the lda instruction in that it handles
1513130561Sobrien   most simple expressions, particularly symbol address loads and
151433965Sjdp   large constants.  */
151533965Sjdp
151633965Sjdpstatic void
1517218822Sdimemit_lda (const expressionS *tok,
1518218822Sdim	  int ntok,
1519218822Sdim	  const void * unused ATTRIBUTE_UNUSED)
152033965Sjdp{
152133965Sjdp  int basereg;
152233965Sjdp
152333965Sjdp  if (ntok == 2)
152433965Sjdp    basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register);
152533965Sjdp  else
152633965Sjdp    basereg = tok[2].X_add_number;
152733965Sjdp
152889857Sobrien  (void) load_expression (tok[0].X_add_number, &tok[1], &basereg, NULL);
152933965Sjdp}
153033965Sjdp
153133965Sjdp/* The ldah macro differs from the ldah instruction in that it has $31
153233965Sjdp   as an implied base register.  */
153333965Sjdp
153433965Sjdpstatic void
1535218822Sdimemit_ldah (const expressionS *tok,
1536218822Sdim	   int ntok ATTRIBUTE_UNUSED,
1537218822Sdim	   const void * unused ATTRIBUTE_UNUSED)
153833965Sjdp{
153933965Sjdp  expressionS newtok[3];
154033965Sjdp
154133965Sjdp  newtok[0] = tok[0];
154233965Sjdp  newtok[1] = tok[1];
154333965Sjdp  set_tok_preg (newtok[2], AXP_REG_ZERO);
154433965Sjdp
154533965Sjdp  assemble_tokens ("ldah", newtok, 3, 0);
154633965Sjdp}
154733965Sjdp
1548218822Sdim/* Called internally to handle all alignment needs.  This takes care
1549218822Sdim   of eliding calls to frag_align if'n the cached current alignment
1550218822Sdim   says we've already got it, as well as taking care of the auto-align
1551218822Sdim   feature wrt labels.  */
1552218822Sdim
1553218822Sdimstatic void
1554218822Sdimalpha_align (int n,
1555218822Sdim	     char *pfill,
1556218822Sdim	     symbolS *label,
1557218822Sdim	     int force ATTRIBUTE_UNUSED)
1558218822Sdim{
1559218822Sdim  if (alpha_current_align >= n)
1560218822Sdim    return;
1561218822Sdim
1562218822Sdim  if (pfill == NULL)
1563218822Sdim    {
1564218822Sdim      if (subseg_text_p (now_seg))
1565218822Sdim	frag_align_code (n, 0);
1566218822Sdim      else
1567218822Sdim	frag_align (n, 0, 0);
1568218822Sdim    }
1569218822Sdim  else
1570218822Sdim    frag_align (n, *pfill, 0);
1571218822Sdim
1572218822Sdim  alpha_current_align = n;
1573218822Sdim
1574218822Sdim  if (label != NULL && S_GET_SEGMENT (label) == now_seg)
1575218822Sdim    {
1576218822Sdim      symbol_set_frag (label, frag_now);
1577218822Sdim      S_SET_VALUE (label, (valueT) frag_now_fix ());
1578218822Sdim    }
1579218822Sdim
1580218822Sdim  record_alignment (now_seg, n);
1581218822Sdim
1582218822Sdim  /* ??? If alpha_flag_relax && force && elf, record the requested alignment
1583218822Sdim     in a reloc for the linker to see.  */
1584218822Sdim}
1585218822Sdim
1586218822Sdim/* Actually output an instruction with its fixup.  */
1587218822Sdim
1588218822Sdimstatic void
1589218822Sdimemit_insn (struct alpha_insn *insn)
1590218822Sdim{
1591218822Sdim  char *f;
1592218822Sdim  int i;
1593218822Sdim
1594218822Sdim  /* Take care of alignment duties.  */
1595218822Sdim  if (alpha_auto_align_on && alpha_current_align < 2)
1596218822Sdim    alpha_align (2, (char *) NULL, alpha_insn_label, 0);
1597218822Sdim  if (alpha_current_align > 2)
1598218822Sdim    alpha_current_align = 2;
1599218822Sdim  alpha_insn_label = NULL;
1600218822Sdim
1601218822Sdim  /* Write out the instruction.  */
1602218822Sdim  f = frag_more (4);
1603218822Sdim  md_number_to_chars (f, insn->insn, 4);
1604218822Sdim
1605218822Sdim#ifdef OBJ_ELF
1606218822Sdim  dwarf2_emit_insn (4);
1607218822Sdim#endif
1608218822Sdim
1609218822Sdim  /* Apply the fixups in order.  */
1610218822Sdim  for (i = 0; i < insn->nfixups; ++i)
1611218822Sdim    {
1612218822Sdim      const struct alpha_operand *operand = (const struct alpha_operand *) 0;
1613218822Sdim      struct alpha_fixup *fixup = &insn->fixups[i];
1614218822Sdim      struct alpha_reloc_tag *info = NULL;
1615218822Sdim      int size, pcrel;
1616218822Sdim      fixS *fixP;
1617218822Sdim
1618218822Sdim      /* Some fixups are only used internally and so have no howto.  */
1619218822Sdim      if ((int) fixup->reloc < 0)
1620218822Sdim	{
1621218822Sdim	  operand = &alpha_operands[-(int) fixup->reloc];
1622218822Sdim	  size = 4;
1623218822Sdim	  pcrel = ((operand->flags & AXP_OPERAND_RELATIVE) != 0);
1624218822Sdim	}
1625218822Sdim      else if (fixup->reloc > BFD_RELOC_UNUSED
1626218822Sdim	       || fixup->reloc == BFD_RELOC_ALPHA_GPDISP_HI16
1627218822Sdim	       || fixup->reloc == BFD_RELOC_ALPHA_GPDISP_LO16)
1628218822Sdim	{
1629218822Sdim	  size = 2;
1630218822Sdim	  pcrel = 0;
1631218822Sdim	}
1632218822Sdim      else
1633218822Sdim	{
1634218822Sdim	  reloc_howto_type *reloc_howto
1635218822Sdim	    = bfd_reloc_type_lookup (stdoutput, fixup->reloc);
1636218822Sdim	  assert (reloc_howto);
1637218822Sdim
1638218822Sdim	  size = bfd_get_reloc_size (reloc_howto);
1639218822Sdim	  assert (size >= 1 && size <= 4);
1640218822Sdim
1641218822Sdim	  pcrel = reloc_howto->pc_relative;
1642218822Sdim	}
1643218822Sdim
1644218822Sdim      fixP = fix_new_exp (frag_now, f - frag_now->fr_literal, size,
1645218822Sdim			  &fixup->exp, pcrel, fixup->reloc);
1646218822Sdim
1647218822Sdim      /* Turn off complaints that the addend is too large for some fixups,
1648218822Sdim         and copy in the sequence number for the explicit relocations.  */
1649218822Sdim      switch (fixup->reloc)
1650218822Sdim	{
1651218822Sdim	case BFD_RELOC_ALPHA_HINT:
1652218822Sdim	case BFD_RELOC_GPREL32:
1653218822Sdim	case BFD_RELOC_GPREL16:
1654218822Sdim	case BFD_RELOC_ALPHA_GPREL_HI16:
1655218822Sdim	case BFD_RELOC_ALPHA_GPREL_LO16:
1656218822Sdim	case BFD_RELOC_ALPHA_GOTDTPREL16:
1657218822Sdim	case BFD_RELOC_ALPHA_DTPREL_HI16:
1658218822Sdim	case BFD_RELOC_ALPHA_DTPREL_LO16:
1659218822Sdim	case BFD_RELOC_ALPHA_DTPREL16:
1660218822Sdim	case BFD_RELOC_ALPHA_GOTTPREL16:
1661218822Sdim	case BFD_RELOC_ALPHA_TPREL_HI16:
1662218822Sdim	case BFD_RELOC_ALPHA_TPREL_LO16:
1663218822Sdim	case BFD_RELOC_ALPHA_TPREL16:
1664218822Sdim	  fixP->fx_no_overflow = 1;
1665218822Sdim	  break;
1666218822Sdim
1667218822Sdim	case BFD_RELOC_ALPHA_GPDISP_HI16:
1668218822Sdim	  fixP->fx_no_overflow = 1;
1669218822Sdim	  fixP->fx_addsy = section_symbol (now_seg);
1670218822Sdim	  fixP->fx_offset = 0;
1671218822Sdim
1672218822Sdim	  info = get_alpha_reloc_tag (insn->sequence);
1673218822Sdim	  if (++info->n_master > 1)
1674218822Sdim	    as_bad (_("too many ldah insns for !gpdisp!%ld"), insn->sequence);
1675218822Sdim	  if (info->segment != now_seg)
1676218822Sdim	    as_bad (_("both insns for !gpdisp!%ld must be in the same section"),
1677218822Sdim		    insn->sequence);
1678218822Sdim	  fixP->tc_fix_data.info = info;
1679218822Sdim	  break;
1680218822Sdim
1681218822Sdim	case BFD_RELOC_ALPHA_GPDISP_LO16:
1682218822Sdim	  fixP->fx_no_overflow = 1;
1683218822Sdim
1684218822Sdim	  info = get_alpha_reloc_tag (insn->sequence);
1685218822Sdim	  if (++info->n_slaves > 1)
1686218822Sdim	    as_bad (_("too many lda insns for !gpdisp!%ld"), insn->sequence);
1687218822Sdim	  if (info->segment != now_seg)
1688218822Sdim	    as_bad (_("both insns for !gpdisp!%ld must be in the same section"),
1689218822Sdim		    insn->sequence);
1690218822Sdim	  fixP->tc_fix_data.info = info;
1691218822Sdim	  info->slaves = fixP;
1692218822Sdim	  break;
1693218822Sdim
1694218822Sdim	case BFD_RELOC_ALPHA_LITERAL:
1695218822Sdim	case BFD_RELOC_ALPHA_ELF_LITERAL:
1696218822Sdim	  fixP->fx_no_overflow = 1;
1697218822Sdim
1698218822Sdim	  if (insn->sequence == 0)
1699218822Sdim	    break;
1700218822Sdim	  info = get_alpha_reloc_tag (insn->sequence);
1701218822Sdim	  info->master = fixP;
1702218822Sdim	  info->n_master++;
1703218822Sdim	  if (info->segment != now_seg)
1704218822Sdim	    info->multi_section_p = 1;
1705218822Sdim	  fixP->tc_fix_data.info = info;
1706218822Sdim	  break;
1707218822Sdim
1708218822Sdim#ifdef RELOC_OP_P
1709218822Sdim	case DUMMY_RELOC_LITUSE_ADDR:
1710218822Sdim	  fixP->fx_offset = LITUSE_ALPHA_ADDR;
1711218822Sdim	  goto do_lituse;
1712218822Sdim	case DUMMY_RELOC_LITUSE_BASE:
1713218822Sdim	  fixP->fx_offset = LITUSE_ALPHA_BASE;
1714218822Sdim	  goto do_lituse;
1715218822Sdim	case DUMMY_RELOC_LITUSE_BYTOFF:
1716218822Sdim	  fixP->fx_offset = LITUSE_ALPHA_BYTOFF;
1717218822Sdim	  goto do_lituse;
1718218822Sdim	case DUMMY_RELOC_LITUSE_JSR:
1719218822Sdim	  fixP->fx_offset = LITUSE_ALPHA_JSR;
1720218822Sdim	  goto do_lituse;
1721218822Sdim	case DUMMY_RELOC_LITUSE_TLSGD:
1722218822Sdim	  fixP->fx_offset = LITUSE_ALPHA_TLSGD;
1723218822Sdim	  goto do_lituse;
1724218822Sdim	case DUMMY_RELOC_LITUSE_TLSLDM:
1725218822Sdim	  fixP->fx_offset = LITUSE_ALPHA_TLSLDM;
1726218822Sdim	  goto do_lituse;
1727218822Sdim	case DUMMY_RELOC_LITUSE_JSRDIRECT:
1728218822Sdim	  fixP->fx_offset = LITUSE_ALPHA_JSRDIRECT;
1729218822Sdim	  goto do_lituse;
1730218822Sdim	do_lituse:
1731218822Sdim	  fixP->fx_addsy = section_symbol (now_seg);
1732218822Sdim	  fixP->fx_r_type = BFD_RELOC_ALPHA_LITUSE;
1733218822Sdim
1734218822Sdim	  info = get_alpha_reloc_tag (insn->sequence);
1735218822Sdim	  if (fixup->reloc == DUMMY_RELOC_LITUSE_TLSGD)
1736218822Sdim	    info->saw_lu_tlsgd = 1;
1737218822Sdim	  else if (fixup->reloc == DUMMY_RELOC_LITUSE_TLSLDM)
1738218822Sdim	    info->saw_lu_tlsldm = 1;
1739218822Sdim	  if (++info->n_slaves > 1)
1740218822Sdim	    {
1741218822Sdim	      if (info->saw_lu_tlsgd)
1742218822Sdim		as_bad (_("too many lituse insns for !lituse_tlsgd!%ld"),
1743218822Sdim		        insn->sequence);
1744218822Sdim	      else if (info->saw_lu_tlsldm)
1745218822Sdim		as_bad (_("too many lituse insns for !lituse_tlsldm!%ld"),
1746218822Sdim		        insn->sequence);
1747218822Sdim	    }
1748218822Sdim	  fixP->tc_fix_data.info = info;
1749218822Sdim	  fixP->tc_fix_data.next_reloc = info->slaves;
1750218822Sdim	  info->slaves = fixP;
1751218822Sdim	  if (info->segment != now_seg)
1752218822Sdim	    info->multi_section_p = 1;
1753218822Sdim	  break;
1754218822Sdim
1755218822Sdim	case BFD_RELOC_ALPHA_TLSGD:
1756218822Sdim	  fixP->fx_no_overflow = 1;
1757218822Sdim
1758218822Sdim	  if (insn->sequence == 0)
1759218822Sdim	    break;
1760218822Sdim	  info = get_alpha_reloc_tag (insn->sequence);
1761218822Sdim	  if (info->saw_tlsgd)
1762218822Sdim	    as_bad (_("duplicate !tlsgd!%ld"), insn->sequence);
1763218822Sdim	  else if (info->saw_tlsldm)
1764218822Sdim	    as_bad (_("sequence number in use for !tlsldm!%ld"),
1765218822Sdim		    insn->sequence);
1766218822Sdim	  else
1767218822Sdim	    info->saw_tlsgd = 1;
1768218822Sdim	  fixP->tc_fix_data.info = info;
1769218822Sdim	  break;
1770218822Sdim
1771218822Sdim	case BFD_RELOC_ALPHA_TLSLDM:
1772218822Sdim	  fixP->fx_no_overflow = 1;
1773218822Sdim
1774218822Sdim	  if (insn->sequence == 0)
1775218822Sdim	    break;
1776218822Sdim	  info = get_alpha_reloc_tag (insn->sequence);
1777218822Sdim	  if (info->saw_tlsldm)
1778218822Sdim	    as_bad (_("duplicate !tlsldm!%ld"), insn->sequence);
1779218822Sdim	  else if (info->saw_tlsgd)
1780218822Sdim	    as_bad (_("sequence number in use for !tlsgd!%ld"),
1781218822Sdim		    insn->sequence);
1782218822Sdim	  else
1783218822Sdim	    info->saw_tlsldm = 1;
1784218822Sdim	  fixP->tc_fix_data.info = info;
1785218822Sdim	  break;
1786218822Sdim#endif
1787218822Sdim	default:
1788218822Sdim	  if ((int) fixup->reloc < 0)
1789218822Sdim	    {
1790218822Sdim	      if (operand->flags & AXP_OPERAND_NOOVERFLOW)
1791218822Sdim		fixP->fx_no_overflow = 1;
1792218822Sdim	    }
1793218822Sdim	  break;
1794218822Sdim	}
1795218822Sdim    }
1796218822Sdim}
1797218822Sdim
1798218822Sdim/* Insert an operand value into an instruction.  */
1799218822Sdim
1800218822Sdimstatic unsigned
1801218822Sdiminsert_operand (unsigned insn,
1802218822Sdim		const struct alpha_operand *operand,
1803218822Sdim		offsetT val,
1804218822Sdim		char *file,
1805218822Sdim		unsigned line)
1806218822Sdim{
1807218822Sdim  if (operand->bits != 32 && !(operand->flags & AXP_OPERAND_NOOVERFLOW))
1808218822Sdim    {
1809218822Sdim      offsetT min, max;
1810218822Sdim
1811218822Sdim      if (operand->flags & AXP_OPERAND_SIGNED)
1812218822Sdim	{
1813218822Sdim	  max = (1 << (operand->bits - 1)) - 1;
1814218822Sdim	  min = -(1 << (operand->bits - 1));
1815218822Sdim	}
1816218822Sdim      else
1817218822Sdim	{
1818218822Sdim	  max = (1 << operand->bits) - 1;
1819218822Sdim	  min = 0;
1820218822Sdim	}
1821218822Sdim
1822218822Sdim      if (val < min || val > max)
1823218822Sdim	as_warn_value_out_of_range (_("operand"), val, min, max, file, line);
1824218822Sdim    }
1825218822Sdim
1826218822Sdim  if (operand->insert)
1827218822Sdim    {
1828218822Sdim      const char *errmsg = NULL;
1829218822Sdim
1830218822Sdim      insn = (*operand->insert) (insn, val, &errmsg);
1831218822Sdim      if (errmsg)
1832218822Sdim	as_warn (errmsg);
1833218822Sdim    }
1834218822Sdim  else
1835218822Sdim    insn |= ((val & ((1 << operand->bits) - 1)) << operand->shift);
1836218822Sdim
1837218822Sdim  return insn;
1838218822Sdim}
1839218822Sdim
1840218822Sdim/* Turn an opcode description and a set of arguments into
1841218822Sdim   an instruction and a fixup.  */
1842218822Sdim
1843218822Sdimstatic void
1844218822Sdimassemble_insn (const struct alpha_opcode *opcode,
1845218822Sdim	       const expressionS *tok,
1846218822Sdim	       int ntok,
1847218822Sdim	       struct alpha_insn *insn,
1848218822Sdim	       bfd_reloc_code_real_type reloc)
1849218822Sdim{
1850218822Sdim  const struct alpha_operand *reloc_operand = NULL;
1851218822Sdim  const expressionS *reloc_exp = NULL;
1852218822Sdim  const unsigned char *argidx;
1853218822Sdim  unsigned image;
1854218822Sdim  int tokidx = 0;
1855218822Sdim
1856218822Sdim  memset (insn, 0, sizeof (*insn));
1857218822Sdim  image = opcode->opcode;
1858218822Sdim
1859218822Sdim  for (argidx = opcode->operands; *argidx; ++argidx)
1860218822Sdim    {
1861218822Sdim      const struct alpha_operand *operand = &alpha_operands[*argidx];
1862218822Sdim      const expressionS *t = (const expressionS *) 0;
1863218822Sdim
1864218822Sdim      if (operand->flags & AXP_OPERAND_FAKE)
1865218822Sdim	{
1866218822Sdim	  /* Fake operands take no value and generate no fixup.  */
1867218822Sdim	  image = insert_operand (image, operand, 0, NULL, 0);
1868218822Sdim	  continue;
1869218822Sdim	}
1870218822Sdim
1871218822Sdim      if (tokidx >= ntok)
1872218822Sdim	{
1873218822Sdim	  switch (operand->flags & AXP_OPERAND_OPTIONAL_MASK)
1874218822Sdim	    {
1875218822Sdim	    case AXP_OPERAND_DEFAULT_FIRST:
1876218822Sdim	      t = &tok[0];
1877218822Sdim	      break;
1878218822Sdim	    case AXP_OPERAND_DEFAULT_SECOND:
1879218822Sdim	      t = &tok[1];
1880218822Sdim	      break;
1881218822Sdim	    case AXP_OPERAND_DEFAULT_ZERO:
1882218822Sdim	      {
1883218822Sdim		static expressionS zero_exp;
1884218822Sdim		t = &zero_exp;
1885218822Sdim		zero_exp.X_op = O_constant;
1886218822Sdim		zero_exp.X_unsigned = 1;
1887218822Sdim	      }
1888218822Sdim	      break;
1889218822Sdim	    default:
1890218822Sdim	      abort ();
1891218822Sdim	    }
1892218822Sdim	}
1893218822Sdim      else
1894218822Sdim	t = &tok[tokidx++];
1895218822Sdim
1896218822Sdim      switch (t->X_op)
1897218822Sdim	{
1898218822Sdim	case O_register:
1899218822Sdim	case O_pregister:
1900218822Sdim	case O_cpregister:
1901218822Sdim	  image = insert_operand (image, operand, regno (t->X_add_number),
1902218822Sdim				  NULL, 0);
1903218822Sdim	  break;
1904218822Sdim
1905218822Sdim	case O_constant:
1906218822Sdim	  image = insert_operand (image, operand, t->X_add_number, NULL, 0);
1907218822Sdim	  assert (reloc_operand == NULL);
1908218822Sdim	  reloc_operand = operand;
1909218822Sdim	  reloc_exp = t;
1910218822Sdim	  break;
1911218822Sdim
1912218822Sdim	default:
1913218822Sdim	  /* This is only 0 for fields that should contain registers,
1914218822Sdim	     which means this pattern shouldn't have matched.  */
1915218822Sdim	  if (operand->default_reloc == 0)
1916218822Sdim	    abort ();
1917218822Sdim
1918218822Sdim	  /* There is one special case for which an insn receives two
1919218822Sdim	     relocations, and thus the user-supplied reloc does not
1920218822Sdim	     override the operand reloc.  */
1921218822Sdim	  if (operand->default_reloc == BFD_RELOC_ALPHA_HINT)
1922218822Sdim	    {
1923218822Sdim	      struct alpha_fixup *fixup;
1924218822Sdim
1925218822Sdim	      if (insn->nfixups >= MAX_INSN_FIXUPS)
1926218822Sdim		as_fatal (_("too many fixups"));
1927218822Sdim
1928218822Sdim	      fixup = &insn->fixups[insn->nfixups++];
1929218822Sdim	      fixup->exp = *t;
1930218822Sdim	      fixup->reloc = BFD_RELOC_ALPHA_HINT;
1931218822Sdim	    }
1932218822Sdim	  else
1933218822Sdim	    {
1934218822Sdim	      if (reloc == BFD_RELOC_UNUSED)
1935218822Sdim		reloc = operand->default_reloc;
1936218822Sdim
1937218822Sdim	      assert (reloc_operand == NULL);
1938218822Sdim	      reloc_operand = operand;
1939218822Sdim	      reloc_exp = t;
1940218822Sdim	    }
1941218822Sdim	  break;
1942218822Sdim	}
1943218822Sdim    }
1944218822Sdim
1945218822Sdim  if (reloc != BFD_RELOC_UNUSED)
1946218822Sdim    {
1947218822Sdim      struct alpha_fixup *fixup;
1948218822Sdim
1949218822Sdim      if (insn->nfixups >= MAX_INSN_FIXUPS)
1950218822Sdim	as_fatal (_("too many fixups"));
1951218822Sdim
1952218822Sdim      /* ??? My but this is hacky.  But the OSF/1 assembler uses the same
1953218822Sdim	 relocation tag for both ldah and lda with gpdisp.  Choose the
1954218822Sdim	 correct internal relocation based on the opcode.  */
1955218822Sdim      if (reloc == BFD_RELOC_ALPHA_GPDISP)
1956218822Sdim	{
1957218822Sdim	  if (strcmp (opcode->name, "ldah") == 0)
1958218822Sdim	    reloc = BFD_RELOC_ALPHA_GPDISP_HI16;
1959218822Sdim	  else if (strcmp (opcode->name, "lda") == 0)
1960218822Sdim	    reloc = BFD_RELOC_ALPHA_GPDISP_LO16;
1961218822Sdim	  else
1962218822Sdim	    as_bad (_("invalid relocation for instruction"));
1963218822Sdim	}
1964218822Sdim
1965218822Sdim      /* If this is a real relocation (as opposed to a lituse hint), then
1966218822Sdim	 the relocation width should match the operand width.  */
1967218822Sdim      else if (reloc < BFD_RELOC_UNUSED)
1968218822Sdim	{
1969218822Sdim	  reloc_howto_type *reloc_howto
1970218822Sdim	    = bfd_reloc_type_lookup (stdoutput, reloc);
1971218822Sdim	  if (reloc_howto->bitsize != reloc_operand->bits)
1972218822Sdim	    {
1973218822Sdim	      as_bad (_("invalid relocation for field"));
1974218822Sdim	      return;
1975218822Sdim	    }
1976218822Sdim	}
1977218822Sdim
1978218822Sdim      fixup = &insn->fixups[insn->nfixups++];
1979218822Sdim      if (reloc_exp)
1980218822Sdim	fixup->exp = *reloc_exp;
1981218822Sdim      else
1982218822Sdim	fixup->exp.X_op = O_absent;
1983218822Sdim      fixup->reloc = reloc;
1984218822Sdim    }
1985218822Sdim
1986218822Sdim  insn->insn = image;
1987218822Sdim}
1988218822Sdim
198933965Sjdp/* Handle all "simple" integer register loads -- ldq, ldq_l, ldq_u,
199033965Sjdp   etc.  They differ from the real instructions in that they do simple
199133965Sjdp   expressions like the lda macro.  */
199233965Sjdp
199333965Sjdpstatic void
1994218822Sdimemit_ir_load (const expressionS *tok,
1995218822Sdim	      int ntok,
1996218822Sdim	      const void * opname)
199733965Sjdp{
199889857Sobrien  int basereg;
199989857Sobrien  long lituse;
200033965Sjdp  expressionS newtok[3];
200133965Sjdp  struct alpha_insn insn;
200233965Sjdp
200333965Sjdp  if (ntok == 2)
200433965Sjdp    basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register);
200533965Sjdp  else
200633965Sjdp    basereg = tok[2].X_add_number;
200733965Sjdp
200833965Sjdp  lituse = load_expression (tok[0].X_add_number, &tok[1], &basereg,
200989857Sobrien			    &newtok[1]);
201033965Sjdp
201133965Sjdp  newtok[0] = tok[0];
201233965Sjdp  set_tok_preg (newtok[2], basereg);
201333965Sjdp
201477298Sobrien  assemble_tokens_to_insn ((const char *) opname, newtok, 3, &insn);
201533965Sjdp
201633965Sjdp  if (lituse)
201733965Sjdp    {
201833965Sjdp      assert (insn.nfixups < MAX_INSN_FIXUPS);
201989857Sobrien      insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
202089857Sobrien      insn.fixups[insn.nfixups].exp.X_op = O_absent;
202133965Sjdp      insn.nfixups++;
202289857Sobrien      insn.sequence = lituse;
202333965Sjdp    }
202433965Sjdp
202533965Sjdp  emit_insn (&insn);
202633965Sjdp}
202733965Sjdp
202833965Sjdp/* Handle fp register loads, and both integer and fp register stores.
202933965Sjdp   Again, we handle simple expressions.  */
203033965Sjdp
203133965Sjdpstatic void
2032218822Sdimemit_loadstore (const expressionS *tok,
2033218822Sdim		int ntok,
2034218822Sdim		const void * opname)
203533965Sjdp{
203689857Sobrien  int basereg;
203789857Sobrien  long lituse;
203833965Sjdp  expressionS newtok[3];
203933965Sjdp  struct alpha_insn insn;
204033965Sjdp
204133965Sjdp  if (ntok == 2)
204233965Sjdp    basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register);
204333965Sjdp  else
204433965Sjdp    basereg = tok[2].X_add_number;
204533965Sjdp
204677298Sobrien  if (tok[1].X_op != O_constant || !range_signed_16 (tok[1].X_add_number))
204733965Sjdp    {
204833965Sjdp      if (alpha_noat_on)
204960484Sobrien	as_bad (_("macro requires $at register while noat in effect"));
205033965Sjdp
205189857Sobrien      lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, &newtok[1]);
205233965Sjdp    }
205333965Sjdp  else
205433965Sjdp    {
205533965Sjdp      newtok[1] = tok[1];
205633965Sjdp      lituse = 0;
205733965Sjdp    }
205833965Sjdp
205933965Sjdp  newtok[0] = tok[0];
206033965Sjdp  set_tok_preg (newtok[2], basereg);
206133965Sjdp
206277298Sobrien  assemble_tokens_to_insn ((const char *) opname, newtok, 3, &insn);
206333965Sjdp
206433965Sjdp  if (lituse)
206533965Sjdp    {
206633965Sjdp      assert (insn.nfixups < MAX_INSN_FIXUPS);
206789857Sobrien      insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
206889857Sobrien      insn.fixups[insn.nfixups].exp.X_op = O_absent;
206933965Sjdp      insn.nfixups++;
207089857Sobrien      insn.sequence = lituse;
207133965Sjdp    }
207233965Sjdp
207333965Sjdp  emit_insn (&insn);
207433965Sjdp}
207533965Sjdp
207633965Sjdp/* Load a half-word or byte as an unsigned value.  */
207733965Sjdp
207833965Sjdpstatic void
2079218822Sdimemit_ldXu (const expressionS *tok,
2080218822Sdim	   int ntok,
2081218822Sdim	   const void * vlgsize)
208233965Sjdp{
208333965Sjdp  if (alpha_target & AXP_OPCODE_BWX)
208477298Sobrien    emit_ir_load (tok, ntok, ldXu_op[(long) vlgsize]);
208533965Sjdp  else
208633965Sjdp    {
208733965Sjdp      expressionS newtok[3];
208889857Sobrien      struct alpha_insn insn;
208989857Sobrien      int basereg;
209089857Sobrien      long lituse;
209133965Sjdp
209233965Sjdp      if (alpha_noat_on)
209360484Sobrien	as_bad (_("macro requires $at register while noat in effect"));
209433965Sjdp
209589857Sobrien      if (ntok == 2)
209689857Sobrien	basereg = (tok[1].X_op == O_constant
209789857Sobrien		   ? AXP_REG_ZERO : alpha_gp_register);
209889857Sobrien      else
209989857Sobrien	basereg = tok[2].X_add_number;
210089857Sobrien
2101218822Sdim      /* Emit "lda $at, exp".  */
210289857Sobrien      lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL);
210333965Sjdp
2104218822Sdim      /* Emit "ldq_u targ, 0($at)".  */
210533965Sjdp      newtok[0] = tok[0];
210633965Sjdp      set_tok_const (newtok[1], 0);
210789857Sobrien      set_tok_preg (newtok[2], basereg);
210889857Sobrien      assemble_tokens_to_insn ("ldq_u", newtok, 3, &insn);
210933965Sjdp
211089857Sobrien      if (lituse)
211189857Sobrien	{
211289857Sobrien	  assert (insn.nfixups < MAX_INSN_FIXUPS);
211389857Sobrien	  insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
211489857Sobrien	  insn.fixups[insn.nfixups].exp.X_op = O_absent;
211589857Sobrien	  insn.nfixups++;
211689857Sobrien	  insn.sequence = lituse;
211789857Sobrien	}
211889857Sobrien
211989857Sobrien      emit_insn (&insn);
212089857Sobrien
2121218822Sdim      /* Emit "extXl targ, $at, targ".  */
212289857Sobrien      set_tok_reg (newtok[1], basereg);
212333965Sjdp      newtok[2] = newtok[0];
212489857Sobrien      assemble_tokens_to_insn (extXl_op[(long) vlgsize], newtok, 3, &insn);
212589857Sobrien
212689857Sobrien      if (lituse)
212789857Sobrien	{
212889857Sobrien	  assert (insn.nfixups < MAX_INSN_FIXUPS);
212989857Sobrien	  insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BYTOFF;
213089857Sobrien	  insn.fixups[insn.nfixups].exp.X_op = O_absent;
213189857Sobrien	  insn.nfixups++;
213289857Sobrien	  insn.sequence = lituse;
213389857Sobrien	}
213489857Sobrien
213589857Sobrien      emit_insn (&insn);
213633965Sjdp    }
213733965Sjdp}
213833965Sjdp
213933965Sjdp/* Load a half-word or byte as a signed value.  */
214033965Sjdp
214133965Sjdpstatic void
2142218822Sdimemit_ldX (const expressionS *tok,
2143218822Sdim	  int ntok,
2144218822Sdim	  const void * vlgsize)
214533965Sjdp{
214633965Sjdp  emit_ldXu (tok, ntok, vlgsize);
214777298Sobrien  assemble_tokens (sextX_op[(long) vlgsize], tok, 1, 1);
214833965Sjdp}
214933965Sjdp
215033965Sjdp/* Load an integral value from an unaligned address as an unsigned
215133965Sjdp   value.  */
215233965Sjdp
215333965Sjdpstatic void
2154218822Sdimemit_uldXu (const expressionS *tok,
2155218822Sdim	    int ntok,
2156218822Sdim	    const void * vlgsize)
215733965Sjdp{
215877298Sobrien  long lgsize = (long) vlgsize;
215933965Sjdp  expressionS newtok[3];
216033965Sjdp
216133965Sjdp  if (alpha_noat_on)
216260484Sobrien    as_bad (_("macro requires $at register while noat in effect"));
216333965Sjdp
2164218822Sdim  /* Emit "lda $at, exp".  */
216533965Sjdp  memcpy (newtok, tok, sizeof (expressionS) * ntok);
216633965Sjdp  newtok[0].X_add_number = AXP_REG_AT;
216733965Sjdp  assemble_tokens ("lda", newtok, ntok, 1);
216833965Sjdp
2169218822Sdim  /* Emit "ldq_u $t9, 0($at)".  */
217033965Sjdp  set_tok_reg (newtok[0], AXP_REG_T9);
217133965Sjdp  set_tok_const (newtok[1], 0);
217233965Sjdp  set_tok_preg (newtok[2], AXP_REG_AT);
217333965Sjdp  assemble_tokens ("ldq_u", newtok, 3, 1);
217433965Sjdp
2175218822Sdim  /* Emit "ldq_u $t10, size-1($at)".  */
217633965Sjdp  set_tok_reg (newtok[0], AXP_REG_T10);
217777298Sobrien  set_tok_const (newtok[1], (1 << lgsize) - 1);
217833965Sjdp  assemble_tokens ("ldq_u", newtok, 3, 1);
217933965Sjdp
2180218822Sdim  /* Emit "extXl $t9, $at, $t9".  */
218133965Sjdp  set_tok_reg (newtok[0], AXP_REG_T9);
218233965Sjdp  set_tok_reg (newtok[1], AXP_REG_AT);
218333965Sjdp  set_tok_reg (newtok[2], AXP_REG_T9);
218433965Sjdp  assemble_tokens (extXl_op[lgsize], newtok, 3, 1);
218533965Sjdp
2186218822Sdim  /* Emit "extXh $t10, $at, $t10".  */
218733965Sjdp  set_tok_reg (newtok[0], AXP_REG_T10);
218833965Sjdp  set_tok_reg (newtok[2], AXP_REG_T10);
218933965Sjdp  assemble_tokens (extXh_op[lgsize], newtok, 3, 1);
219033965Sjdp
2191218822Sdim  /* Emit "or $t9, $t10, targ".  */
219233965Sjdp  set_tok_reg (newtok[0], AXP_REG_T9);
219333965Sjdp  set_tok_reg (newtok[1], AXP_REG_T10);
219433965Sjdp  newtok[2] = tok[0];
219533965Sjdp  assemble_tokens ("or", newtok, 3, 1);
219633965Sjdp}
219733965Sjdp
219833965Sjdp/* Load an integral value from an unaligned address as a signed value.
219933965Sjdp   Note that quads should get funneled to the unsigned load since we
220033965Sjdp   don't have to do the sign extension.  */
220133965Sjdp
220233965Sjdpstatic void
2203218822Sdimemit_uldX (const expressionS *tok,
2204218822Sdim	   int ntok,
2205218822Sdim	   const void * vlgsize)
220633965Sjdp{
220733965Sjdp  emit_uldXu (tok, ntok, vlgsize);
220877298Sobrien  assemble_tokens (sextX_op[(long) vlgsize], tok, 1, 1);
220933965Sjdp}
221033965Sjdp
221133965Sjdp/* Implement the ldil macro.  */
221233965Sjdp
221333965Sjdpstatic void
2214218822Sdimemit_ldil (const expressionS *tok,
2215218822Sdim	   int ntok,
2216218822Sdim	   const void * unused ATTRIBUTE_UNUSED)
221733965Sjdp{
221833965Sjdp  expressionS newtok[2];
221933965Sjdp
222077298Sobrien  memcpy (newtok, tok, sizeof (newtok));
222133965Sjdp  newtok[1].X_add_number = sign_extend_32 (tok[1].X_add_number);
222233965Sjdp
222333965Sjdp  assemble_tokens ("lda", newtok, ntok, 1);
222433965Sjdp}
222533965Sjdp
222633965Sjdp/* Store a half-word or byte.  */
222733965Sjdp
222833965Sjdpstatic void
2229218822Sdimemit_stX (const expressionS *tok,
2230218822Sdim	  int ntok,
2231218822Sdim	  const void * vlgsize)
223233965Sjdp{
223377298Sobrien  int lgsize = (int) (long) vlgsize;
223433965Sjdp
223533965Sjdp  if (alpha_target & AXP_OPCODE_BWX)
223633965Sjdp    emit_loadstore (tok, ntok, stX_op[lgsize]);
223733965Sjdp  else
223833965Sjdp    {
223933965Sjdp      expressionS newtok[3];
224089857Sobrien      struct alpha_insn insn;
224189857Sobrien      int basereg;
224289857Sobrien      long lituse;
224333965Sjdp
224433965Sjdp      if (alpha_noat_on)
224577298Sobrien	as_bad (_("macro requires $at register while noat in effect"));
224633965Sjdp
224789857Sobrien      if (ntok == 2)
224889857Sobrien	basereg = (tok[1].X_op == O_constant
224989857Sobrien		   ? AXP_REG_ZERO : alpha_gp_register);
225089857Sobrien      else
225189857Sobrien	basereg = tok[2].X_add_number;
225289857Sobrien
2253218822Sdim      /* Emit "lda $at, exp".  */
225489857Sobrien      lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL);
225533965Sjdp
2256218822Sdim      /* Emit "ldq_u $t9, 0($at)".  */
225733965Sjdp      set_tok_reg (newtok[0], AXP_REG_T9);
225833965Sjdp      set_tok_const (newtok[1], 0);
225989857Sobrien      set_tok_preg (newtok[2], basereg);
226089857Sobrien      assemble_tokens_to_insn ("ldq_u", newtok, 3, &insn);
226133965Sjdp
226289857Sobrien      if (lituse)
226389857Sobrien	{
226489857Sobrien	  assert (insn.nfixups < MAX_INSN_FIXUPS);
226589857Sobrien	  insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
226689857Sobrien	  insn.fixups[insn.nfixups].exp.X_op = O_absent;
226789857Sobrien	  insn.nfixups++;
226889857Sobrien	  insn.sequence = lituse;
226989857Sobrien	}
227089857Sobrien
227189857Sobrien      emit_insn (&insn);
227289857Sobrien
2273218822Sdim      /* Emit "insXl src, $at, $t10".  */
227433965Sjdp      newtok[0] = tok[0];
227589857Sobrien      set_tok_reg (newtok[1], basereg);
227633965Sjdp      set_tok_reg (newtok[2], AXP_REG_T10);
227789857Sobrien      assemble_tokens_to_insn (insXl_op[lgsize], newtok, 3, &insn);
227833965Sjdp
227989857Sobrien      if (lituse)
228089857Sobrien	{
228189857Sobrien	  assert (insn.nfixups < MAX_INSN_FIXUPS);
228289857Sobrien	  insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BYTOFF;
228389857Sobrien	  insn.fixups[insn.nfixups].exp.X_op = O_absent;
228489857Sobrien	  insn.nfixups++;
228589857Sobrien	  insn.sequence = lituse;
228689857Sobrien	}
228789857Sobrien
228889857Sobrien      emit_insn (&insn);
228989857Sobrien
2290218822Sdim      /* Emit "mskXl $t9, $at, $t9".  */
229133965Sjdp      set_tok_reg (newtok[0], AXP_REG_T9);
229233965Sjdp      newtok[2] = newtok[0];
229389857Sobrien      assemble_tokens_to_insn (mskXl_op[lgsize], newtok, 3, &insn);
229433965Sjdp
229589857Sobrien      if (lituse)
229689857Sobrien	{
229789857Sobrien	  assert (insn.nfixups < MAX_INSN_FIXUPS);
229889857Sobrien	  insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BYTOFF;
229989857Sobrien	  insn.fixups[insn.nfixups].exp.X_op = O_absent;
230089857Sobrien	  insn.nfixups++;
230189857Sobrien	  insn.sequence = lituse;
230289857Sobrien	}
230389857Sobrien
230489857Sobrien      emit_insn (&insn);
230589857Sobrien
2306218822Sdim      /* Emit "or $t9, $t10, $t9".  */
230733965Sjdp      set_tok_reg (newtok[1], AXP_REG_T10);
230833965Sjdp      assemble_tokens ("or", newtok, 3, 1);
230933965Sjdp
2310218822Sdim      /* Emit "stq_u $t9, 0($at).  */
231189857Sobrien      set_tok_const(newtok[1], 0);
231233965Sjdp      set_tok_preg (newtok[2], AXP_REG_AT);
231389857Sobrien      assemble_tokens_to_insn ("stq_u", newtok, 3, &insn);
231489857Sobrien
231589857Sobrien      if (lituse)
231689857Sobrien	{
231789857Sobrien	  assert (insn.nfixups < MAX_INSN_FIXUPS);
231889857Sobrien	  insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
231989857Sobrien	  insn.fixups[insn.nfixups].exp.X_op = O_absent;
232089857Sobrien	  insn.nfixups++;
232189857Sobrien	  insn.sequence = lituse;
232289857Sobrien	}
232389857Sobrien
232489857Sobrien      emit_insn (&insn);
232533965Sjdp    }
232633965Sjdp}
232733965Sjdp
232833965Sjdp/* Store an integer to an unaligned address.  */
232933965Sjdp
233033965Sjdpstatic void
2331218822Sdimemit_ustX (const expressionS *tok,
2332218822Sdim	   int ntok,
2333218822Sdim	   const void * vlgsize)
233433965Sjdp{
233577298Sobrien  int lgsize = (int) (long) vlgsize;
233633965Sjdp  expressionS newtok[3];
233733965Sjdp
2338218822Sdim  /* Emit "lda $at, exp".  */
233933965Sjdp  memcpy (newtok, tok, sizeof (expressionS) * ntok);
234033965Sjdp  newtok[0].X_add_number = AXP_REG_AT;
234133965Sjdp  assemble_tokens ("lda", newtok, ntok, 1);
234233965Sjdp
2343218822Sdim  /* Emit "ldq_u $9, 0($at)".  */
234433965Sjdp  set_tok_reg (newtok[0], AXP_REG_T9);
234533965Sjdp  set_tok_const (newtok[1], 0);
234633965Sjdp  set_tok_preg (newtok[2], AXP_REG_AT);
234733965Sjdp  assemble_tokens ("ldq_u", newtok, 3, 1);
234833965Sjdp
2349218822Sdim  /* Emit "ldq_u $10, size-1($at)".  */
235033965Sjdp  set_tok_reg (newtok[0], AXP_REG_T10);
235177298Sobrien  set_tok_const (newtok[1], (1 << lgsize) - 1);
235233965Sjdp  assemble_tokens ("ldq_u", newtok, 3, 1);
235333965Sjdp
2354218822Sdim  /* Emit "insXl src, $at, $t11".  */
235533965Sjdp  newtok[0] = tok[0];
235633965Sjdp  set_tok_reg (newtok[1], AXP_REG_AT);
235733965Sjdp  set_tok_reg (newtok[2], AXP_REG_T11);
235833965Sjdp  assemble_tokens (insXl_op[lgsize], newtok, 3, 1);
235933965Sjdp
2360218822Sdim  /* Emit "insXh src, $at, $t12".  */
236133965Sjdp  set_tok_reg (newtok[2], AXP_REG_T12);
236233965Sjdp  assemble_tokens (insXh_op[lgsize], newtok, 3, 1);
236333965Sjdp
2364218822Sdim  /* Emit "mskXl $t9, $at, $t9".  */
236533965Sjdp  set_tok_reg (newtok[0], AXP_REG_T9);
236633965Sjdp  newtok[2] = newtok[0];
236733965Sjdp  assemble_tokens (mskXl_op[lgsize], newtok, 3, 1);
236833965Sjdp
2369218822Sdim  /* Emit "mskXh $t10, $at, $t10".  */
237033965Sjdp  set_tok_reg (newtok[0], AXP_REG_T10);
237133965Sjdp  newtok[2] = newtok[0];
237233965Sjdp  assemble_tokens (mskXh_op[lgsize], newtok, 3, 1);
237333965Sjdp
2374218822Sdim  /* Emit "or $t9, $t11, $t9".  */
237533965Sjdp  set_tok_reg (newtok[0], AXP_REG_T9);
237633965Sjdp  set_tok_reg (newtok[1], AXP_REG_T11);
237733965Sjdp  newtok[2] = newtok[0];
237833965Sjdp  assemble_tokens ("or", newtok, 3, 1);
237933965Sjdp
2380218822Sdim  /* Emit "or $t10, $t12, $t10".  */
238133965Sjdp  set_tok_reg (newtok[0], AXP_REG_T10);
238233965Sjdp  set_tok_reg (newtok[1], AXP_REG_T12);
238333965Sjdp  newtok[2] = newtok[0];
238433965Sjdp  assemble_tokens ("or", newtok, 3, 1);
238533965Sjdp
2386218822Sdim  /* Emit "stq_u $t10, size-1($at)".  */
2387218822Sdim  set_tok_reg (newtok[0], AXP_REG_T10);
2388218822Sdim  set_tok_const (newtok[1], (1 << lgsize) - 1);
2389218822Sdim  set_tok_preg (newtok[2], AXP_REG_AT);
2390218822Sdim  assemble_tokens ("stq_u", newtok, 3, 1);
239133965Sjdp
2392218822Sdim  /* Emit "stq_u $t9, 0($at)".  */
239333965Sjdp  set_tok_reg (newtok[0], AXP_REG_T9);
239433965Sjdp  set_tok_const (newtok[1], 0);
239533965Sjdp  assemble_tokens ("stq_u", newtok, 3, 1);
239633965Sjdp}
239733965Sjdp
239833965Sjdp/* Sign extend a half-word or byte.  The 32-bit sign extend is
239933965Sjdp   implemented as "addl $31, $r, $t" in the opcode table.  */
240033965Sjdp
240133965Sjdpstatic void
2402218822Sdimemit_sextX (const expressionS *tok,
2403218822Sdim	    int ntok,
2404218822Sdim	    const void * vlgsize)
240533965Sjdp{
240677298Sobrien  long lgsize = (long) vlgsize;
240733965Sjdp
240833965Sjdp  if (alpha_target & AXP_OPCODE_BWX)
240933965Sjdp    assemble_tokens (sextX_op[lgsize], tok, ntok, 0);
241033965Sjdp  else
241133965Sjdp    {
241233965Sjdp      int bitshift = 64 - 8 * (1 << lgsize);
241333965Sjdp      expressionS newtok[3];
241433965Sjdp
2415218822Sdim      /* Emit "sll src,bits,dst".  */
241633965Sjdp      newtok[0] = tok[0];
241733965Sjdp      set_tok_const (newtok[1], bitshift);
241833965Sjdp      newtok[2] = tok[ntok - 1];
241933965Sjdp      assemble_tokens ("sll", newtok, 3, 1);
242033965Sjdp
2421218822Sdim      /* Emit "sra dst,bits,dst".  */
242233965Sjdp      newtok[0] = newtok[2];
242333965Sjdp      assemble_tokens ("sra", newtok, 3, 1);
242433965Sjdp    }
242533965Sjdp}
242633965Sjdp
242733965Sjdp/* Implement the division and modulus macros.  */
242833965Sjdp
242933965Sjdp#ifdef OBJ_EVAX
243033965Sjdp
243133965Sjdp/* Make register usage like in normal procedure call.
243233965Sjdp   Don't clobber PV and RA.  */
243333965Sjdp
243433965Sjdpstatic void
2435218822Sdimemit_division (const expressionS *tok,
2436218822Sdim	       int ntok,
2437218822Sdim	       const void * symname)
243833965Sjdp{
243933965Sjdp  /* DIVISION and MODULUS. Yech.
2440218822Sdim
2441130561Sobrien     Convert
2442130561Sobrien        OP x,y,result
2443130561Sobrien     to
2444130561Sobrien        mov x,R16	# if x != R16
2445130561Sobrien        mov y,R17	# if y != R17
2446130561Sobrien        lda AT,__OP
2447130561Sobrien        jsr AT,(AT),0
2448130561Sobrien        mov R0,result
2449218822Sdim
2450130561Sobrien     with appropriate optimizations if R0,R16,R17 are the registers
2451130561Sobrien     specified by the compiler.  */
245233965Sjdp
245333965Sjdp  int xr, yr, rr;
245433965Sjdp  symbolS *sym;
245533965Sjdp  expressionS newtok[3];
245633965Sjdp
245733965Sjdp  xr = regno (tok[0].X_add_number);
245833965Sjdp  yr = regno (tok[1].X_add_number);
245933965Sjdp
246033965Sjdp  if (ntok < 3)
246133965Sjdp    rr = xr;
246233965Sjdp  else
246333965Sjdp    rr = regno (tok[2].X_add_number);
246433965Sjdp
2465130561Sobrien  /* Move the operands into the right place.  */
246633965Sjdp  if (yr == AXP_REG_R16 && xr == AXP_REG_R17)
246733965Sjdp    {
2468130561Sobrien      /* They are in exactly the wrong order -- swap through AT.  */
246933965Sjdp      if (alpha_noat_on)
247060484Sobrien	as_bad (_("macro requires $at register while noat in effect"));
247133965Sjdp
247233965Sjdp      set_tok_reg (newtok[0], AXP_REG_R16);
247333965Sjdp      set_tok_reg (newtok[1], AXP_REG_AT);
247433965Sjdp      assemble_tokens ("mov", newtok, 2, 1);
247533965Sjdp
247633965Sjdp      set_tok_reg (newtok[0], AXP_REG_R17);
247733965Sjdp      set_tok_reg (newtok[1], AXP_REG_R16);
247833965Sjdp      assemble_tokens ("mov", newtok, 2, 1);
247933965Sjdp
248033965Sjdp      set_tok_reg (newtok[0], AXP_REG_AT);
248133965Sjdp      set_tok_reg (newtok[1], AXP_REG_R17);
248233965Sjdp      assemble_tokens ("mov", newtok, 2, 1);
248333965Sjdp    }
248433965Sjdp  else
248533965Sjdp    {
248633965Sjdp      if (yr == AXP_REG_R16)
248733965Sjdp	{
248833965Sjdp	  set_tok_reg (newtok[0], AXP_REG_R16);
248933965Sjdp	  set_tok_reg (newtok[1], AXP_REG_R17);
249033965Sjdp	  assemble_tokens ("mov", newtok, 2, 1);
249133965Sjdp	}
249233965Sjdp
249333965Sjdp      if (xr != AXP_REG_R16)
249433965Sjdp	{
249533965Sjdp	  set_tok_reg (newtok[0], xr);
249633965Sjdp	  set_tok_reg (newtok[1], AXP_REG_R16);
249777298Sobrien	  assemble_tokens ("mov", newtok, 2, 1);
249833965Sjdp	}
249933965Sjdp
250033965Sjdp      if (yr != AXP_REG_R16 && yr != AXP_REG_R17)
250133965Sjdp	{
250233965Sjdp	  set_tok_reg (newtok[0], yr);
250333965Sjdp	  set_tok_reg (newtok[1], AXP_REG_R17);
250433965Sjdp	  assemble_tokens ("mov", newtok, 2, 1);
250533965Sjdp	}
250633965Sjdp    }
250733965Sjdp
250877298Sobrien  sym = symbol_find_or_make ((const char *) symname);
250933965Sjdp
251033965Sjdp  set_tok_reg (newtok[0], AXP_REG_AT);
251133965Sjdp  set_tok_sym (newtok[1], sym, 0);
251233965Sjdp  assemble_tokens ("lda", newtok, 2, 1);
251333965Sjdp
2514130561Sobrien  /* Call the division routine.  */
251533965Sjdp  set_tok_reg (newtok[0], AXP_REG_AT);
251633965Sjdp  set_tok_cpreg (newtok[1], AXP_REG_AT);
251733965Sjdp  set_tok_const (newtok[2], 0);
251833965Sjdp  assemble_tokens ("jsr", newtok, 3, 1);
251933965Sjdp
2520130561Sobrien  /* Move the result to the right place.  */
252133965Sjdp  if (rr != AXP_REG_R0)
252233965Sjdp    {
252333965Sjdp      set_tok_reg (newtok[0], AXP_REG_R0);
252433965Sjdp      set_tok_reg (newtok[1], rr);
252533965Sjdp      assemble_tokens ("mov", newtok, 2, 1);
252633965Sjdp    }
252733965Sjdp}
252833965Sjdp
252933965Sjdp#else /* !OBJ_EVAX */
253033965Sjdp
253133965Sjdpstatic void
2532218822Sdimemit_division (const expressionS *tok,
2533218822Sdim	       int ntok,
2534218822Sdim	       const void * symname)
253533965Sjdp{
253633965Sjdp  /* DIVISION and MODULUS. Yech.
2537130561Sobrien     Convert
2538130561Sobrien        OP x,y,result
2539130561Sobrien     to
2540130561Sobrien        lda pv,__OP
2541130561Sobrien        mov x,t10
2542130561Sobrien        mov y,t11
2543130561Sobrien        jsr t9,(pv),__OP
2544130561Sobrien        mov t12,result
2545218822Sdim
2546130561Sobrien     with appropriate optimizations if t10,t11,t12 are the registers
2547130561Sobrien     specified by the compiler.  */
254833965Sjdp
254933965Sjdp  int xr, yr, rr;
255033965Sjdp  symbolS *sym;
255133965Sjdp  expressionS newtok[3];
255233965Sjdp
255333965Sjdp  xr = regno (tok[0].X_add_number);
255433965Sjdp  yr = regno (tok[1].X_add_number);
255533965Sjdp
255633965Sjdp  if (ntok < 3)
255733965Sjdp    rr = xr;
255833965Sjdp  else
255933965Sjdp    rr = regno (tok[2].X_add_number);
256033965Sjdp
256177298Sobrien  sym = symbol_find_or_make ((const char *) symname);
256233965Sjdp
2563130561Sobrien  /* Move the operands into the right place.  */
256433965Sjdp  if (yr == AXP_REG_T10 && xr == AXP_REG_T11)
256533965Sjdp    {
2566130561Sobrien      /* They are in exactly the wrong order -- swap through AT.  */
256733965Sjdp      if (alpha_noat_on)
256860484Sobrien	as_bad (_("macro requires $at register while noat in effect"));
256933965Sjdp
257033965Sjdp      set_tok_reg (newtok[0], AXP_REG_T10);
257133965Sjdp      set_tok_reg (newtok[1], AXP_REG_AT);
257233965Sjdp      assemble_tokens ("mov", newtok, 2, 1);
257333965Sjdp
257433965Sjdp      set_tok_reg (newtok[0], AXP_REG_T11);
257533965Sjdp      set_tok_reg (newtok[1], AXP_REG_T10);
257633965Sjdp      assemble_tokens ("mov", newtok, 2, 1);
257733965Sjdp
257833965Sjdp      set_tok_reg (newtok[0], AXP_REG_AT);
257933965Sjdp      set_tok_reg (newtok[1], AXP_REG_T11);
258033965Sjdp      assemble_tokens ("mov", newtok, 2, 1);
258133965Sjdp    }
258233965Sjdp  else
258333965Sjdp    {
258433965Sjdp      if (yr == AXP_REG_T10)
258533965Sjdp	{
258633965Sjdp	  set_tok_reg (newtok[0], AXP_REG_T10);
258733965Sjdp	  set_tok_reg (newtok[1], AXP_REG_T11);
258833965Sjdp	  assemble_tokens ("mov", newtok, 2, 1);
258933965Sjdp	}
259033965Sjdp
259133965Sjdp      if (xr != AXP_REG_T10)
259233965Sjdp	{
259333965Sjdp	  set_tok_reg (newtok[0], xr);
259433965Sjdp	  set_tok_reg (newtok[1], AXP_REG_T10);
259577298Sobrien	  assemble_tokens ("mov", newtok, 2, 1);
259633965Sjdp	}
259733965Sjdp
259833965Sjdp      if (yr != AXP_REG_T10 && yr != AXP_REG_T11)
259933965Sjdp	{
260033965Sjdp	  set_tok_reg (newtok[0], yr);
260133965Sjdp	  set_tok_reg (newtok[1], AXP_REG_T11);
260233965Sjdp	  assemble_tokens ("mov", newtok, 2, 1);
260333965Sjdp	}
260433965Sjdp    }
260533965Sjdp
2606130561Sobrien  /* Call the division routine.  */
260733965Sjdp  set_tok_reg (newtok[0], AXP_REG_T9);
260833965Sjdp  set_tok_sym (newtok[1], sym, 0);
260933965Sjdp  assemble_tokens ("jsr", newtok, 2, 1);
261033965Sjdp
2611130561Sobrien  /* Reload the GP register.  */
261233965Sjdp#ifdef OBJ_AOUT
261333965SjdpFIXME
261433965Sjdp#endif
261533965Sjdp#if defined(OBJ_ECOFF) || defined(OBJ_ELF)
261633965Sjdp  set_tok_reg (newtok[0], alpha_gp_register);
261733965Sjdp  set_tok_const (newtok[1], 0);
261833965Sjdp  set_tok_preg (newtok[2], AXP_REG_T9);
261933965Sjdp  assemble_tokens ("ldgp", newtok, 3, 1);
262033965Sjdp#endif
262133965Sjdp
2622130561Sobrien  /* Move the result to the right place.  */
262333965Sjdp  if (rr != AXP_REG_T12)
262433965Sjdp    {
262533965Sjdp      set_tok_reg (newtok[0], AXP_REG_T12);
262633965Sjdp      set_tok_reg (newtok[1], rr);
262733965Sjdp      assemble_tokens ("mov", newtok, 2, 1);
262833965Sjdp    }
262933965Sjdp}
263033965Sjdp
263133965Sjdp#endif /* !OBJ_EVAX */
263233965Sjdp
263333965Sjdp/* The jsr and jmp macros differ from their instruction counterparts
263433965Sjdp   in that they can load the target address and default most
263533965Sjdp   everything.  */
263633965Sjdp
263733965Sjdpstatic void
2638218822Sdimemit_jsrjmp (const expressionS *tok,
2639218822Sdim	     int ntok,
2640218822Sdim	     const void * vopname)
264133965Sjdp{
264233965Sjdp  const char *opname = (const char *) vopname;
264333965Sjdp  struct alpha_insn insn;
264433965Sjdp  expressionS newtok[3];
264589857Sobrien  int r, tokidx = 0;
264689857Sobrien  long lituse = 0;
264733965Sjdp
264833965Sjdp  if (tokidx < ntok && tok[tokidx].X_op == O_register)
264933965Sjdp    r = regno (tok[tokidx++].X_add_number);
265033965Sjdp  else
265133965Sjdp    r = strcmp (opname, "jmp") == 0 ? AXP_REG_ZERO : AXP_REG_RA;
265233965Sjdp
265333965Sjdp  set_tok_reg (newtok[0], r);
265433965Sjdp
265533965Sjdp  if (tokidx < ntok &&
265633965Sjdp      (tok[tokidx].X_op == O_pregister || tok[tokidx].X_op == O_cpregister))
265733965Sjdp    r = regno (tok[tokidx++].X_add_number);
265833965Sjdp#ifdef OBJ_EVAX
2659218822Sdim  /* Keep register if jsr $n.<sym>.  */
266033965Sjdp#else
266133965Sjdp  else
266233965Sjdp    {
266333965Sjdp      int basereg = alpha_gp_register;
266489857Sobrien      lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], &basereg, NULL);
266533965Sjdp    }
266633965Sjdp#endif
266733965Sjdp
266833965Sjdp  set_tok_cpreg (newtok[1], r);
266933965Sjdp
267033965Sjdp#ifdef OBJ_EVAX
267133965Sjdp  /* FIXME: Add hint relocs to BFD for evax.  */
267233965Sjdp#else
267333965Sjdp  if (tokidx < ntok)
267433965Sjdp    newtok[2] = tok[tokidx];
267533965Sjdp  else
267633965Sjdp#endif
267733965Sjdp    set_tok_const (newtok[2], 0);
267833965Sjdp
267933965Sjdp  assemble_tokens_to_insn (opname, newtok, 3, &insn);
268033965Sjdp
268133965Sjdp  if (lituse)
268233965Sjdp    {
268333965Sjdp      assert (insn.nfixups < MAX_INSN_FIXUPS);
268489857Sobrien      insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_JSR;
268589857Sobrien      insn.fixups[insn.nfixups].exp.X_op = O_absent;
268633965Sjdp      insn.nfixups++;
268789857Sobrien      insn.sequence = lituse;
268833965Sjdp    }
268933965Sjdp
269033965Sjdp  emit_insn (&insn);
269133965Sjdp}
269233965Sjdp
269333965Sjdp/* The ret and jcr instructions differ from their instruction
269433965Sjdp   counterparts in that everything can be defaulted.  */
269533965Sjdp
269633965Sjdpstatic void
2697218822Sdimemit_retjcr (const expressionS *tok,
2698218822Sdim	     int ntok,
2699218822Sdim	     const void * vopname)
270033965Sjdp{
270177298Sobrien  const char *opname = (const char *) vopname;
270233965Sjdp  expressionS newtok[3];
270333965Sjdp  int r, tokidx = 0;
270433965Sjdp
270533965Sjdp  if (tokidx < ntok && tok[tokidx].X_op == O_register)
270633965Sjdp    r = regno (tok[tokidx++].X_add_number);
270733965Sjdp  else
270833965Sjdp    r = AXP_REG_ZERO;
270933965Sjdp
271033965Sjdp  set_tok_reg (newtok[0], r);
271133965Sjdp
271233965Sjdp  if (tokidx < ntok &&
271333965Sjdp      (tok[tokidx].X_op == O_pregister || tok[tokidx].X_op == O_cpregister))
271433965Sjdp    r = regno (tok[tokidx++].X_add_number);
271533965Sjdp  else
271633965Sjdp    r = AXP_REG_RA;
271733965Sjdp
271833965Sjdp  set_tok_cpreg (newtok[1], r);
271933965Sjdp
272033965Sjdp  if (tokidx < ntok)
272133965Sjdp    newtok[2] = tok[tokidx];
272233965Sjdp  else
272377298Sobrien    set_tok_const (newtok[2], strcmp (opname, "ret") == 0);
272433965Sjdp
272533965Sjdp  assemble_tokens (opname, newtok, 3, 0);
272633965Sjdp}
2727218822Sdim
2728218822Sdim/* Implement the ldgp macro.  */
2729218822Sdim
2730218822Sdimstatic void
2731218822Sdimemit_ldgp (const expressionS *tok,
2732218822Sdim	   int ntok ATTRIBUTE_UNUSED,
2733218822Sdim	   const void * unused ATTRIBUTE_UNUSED)
2734218822Sdim{
2735218822Sdim#ifdef OBJ_AOUT
2736218822SdimFIXME
2737218822Sdim#endif
2738218822Sdim#if defined(OBJ_ECOFF) || defined(OBJ_ELF)
2739218822Sdim  /* from "ldgp r1,n(r2)", generate "ldah r1,X(R2); lda r1,Y(r1)"
2740218822Sdim     with appropriate constants and relocations.  */
2741218822Sdim  struct alpha_insn insn;
2742218822Sdim  expressionS newtok[3];
2743218822Sdim  expressionS addend;
2744218822Sdim
2745218822Sdim#ifdef OBJ_ECOFF
2746218822Sdim  if (regno (tok[2].X_add_number) == AXP_REG_PV)
2747218822Sdim    ecoff_set_gp_prolog_size (0);
2748218822Sdim#endif
2749218822Sdim
2750218822Sdim  newtok[0] = tok[0];
2751218822Sdim  set_tok_const (newtok[1], 0);
2752218822Sdim  newtok[2] = tok[2];
2753218822Sdim
2754218822Sdim  assemble_tokens_to_insn ("ldah", newtok, 3, &insn);
2755218822Sdim
2756218822Sdim  addend = tok[1];
2757218822Sdim
2758218822Sdim#ifdef OBJ_ECOFF
2759218822Sdim  if (addend.X_op != O_constant)
2760218822Sdim    as_bad (_("can not resolve expression"));
2761218822Sdim  addend.X_op = O_symbol;
2762218822Sdim  addend.X_add_symbol = alpha_gp_symbol;
2763218822Sdim#endif
2764218822Sdim
2765218822Sdim  insn.nfixups = 1;
2766218822Sdim  insn.fixups[0].exp = addend;
2767218822Sdim  insn.fixups[0].reloc = BFD_RELOC_ALPHA_GPDISP_HI16;
2768218822Sdim  insn.sequence = next_sequence_num;
2769218822Sdim
2770218822Sdim  emit_insn (&insn);
2771218822Sdim
2772218822Sdim  set_tok_preg (newtok[2], tok[0].X_add_number);
2773218822Sdim
2774218822Sdim  assemble_tokens_to_insn ("lda", newtok, 3, &insn);
2775218822Sdim
2776218822Sdim#ifdef OBJ_ECOFF
2777218822Sdim  addend.X_add_number += 4;
2778218822Sdim#endif
2779218822Sdim
2780218822Sdim  insn.nfixups = 1;
2781218822Sdim  insn.fixups[0].exp = addend;
2782218822Sdim  insn.fixups[0].reloc = BFD_RELOC_ALPHA_GPDISP_LO16;
2783218822Sdim  insn.sequence = next_sequence_num--;
2784218822Sdim
2785218822Sdim  emit_insn (&insn);
2786218822Sdim#endif /* OBJ_ECOFF || OBJ_ELF */
2787218822Sdim}
2788218822Sdim
2789218822Sdim/* The macro table.  */
2790218822Sdim
2791218822Sdimstatic const struct alpha_macro alpha_macros[] =
2792218822Sdim{
2793218822Sdim/* Load/Store macros.  */
2794218822Sdim  { "lda",	emit_lda, NULL,
2795218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2796218822Sdim  { "ldah",	emit_ldah, NULL,
2797218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_EOA } },
2798218822Sdim
2799218822Sdim  { "ldl",	emit_ir_load, "ldl",
2800218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2801218822Sdim  { "ldl_l",	emit_ir_load, "ldl_l",
2802218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2803218822Sdim  { "ldq",	emit_ir_load, "ldq",
2804218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2805218822Sdim  { "ldq_l",	emit_ir_load, "ldq_l",
2806218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2807218822Sdim  { "ldq_u",	emit_ir_load, "ldq_u",
2808218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2809218822Sdim  { "ldf",	emit_loadstore, "ldf",
2810218822Sdim    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2811218822Sdim  { "ldg",	emit_loadstore, "ldg",
2812218822Sdim    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2813218822Sdim  { "lds",	emit_loadstore, "lds",
2814218822Sdim    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2815218822Sdim  { "ldt",	emit_loadstore, "ldt",
2816218822Sdim    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2817218822Sdim
2818218822Sdim  { "ldb",	emit_ldX, (void *) 0,
2819218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2820218822Sdim  { "ldbu",	emit_ldXu, (void *) 0,
2821218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2822218822Sdim  { "ldw",	emit_ldX, (void *) 1,
2823218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2824218822Sdim  { "ldwu",	emit_ldXu, (void *) 1,
2825218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2826218822Sdim
2827218822Sdim  { "uldw",	emit_uldX, (void *) 1,
2828218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2829218822Sdim  { "uldwu",	emit_uldXu, (void *) 1,
2830218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2831218822Sdim  { "uldl",	emit_uldX, (void *) 2,
2832218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2833218822Sdim  { "uldlu",	emit_uldXu, (void *) 2,
2834218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2835218822Sdim  { "uldq",	emit_uldXu, (void *) 3,
2836218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2837218822Sdim
2838218822Sdim  { "ldgp",	emit_ldgp, NULL,
2839218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA } },
2840218822Sdim
2841218822Sdim  { "ldi",	emit_lda, NULL,
2842218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_EOA } },
2843218822Sdim  { "ldil",	emit_ldil, NULL,
2844218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_EOA } },
2845218822Sdim  { "ldiq",	emit_lda, NULL,
2846218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_EOA } },
2847218822Sdim
2848218822Sdim  { "stl",	emit_loadstore, "stl",
2849218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2850218822Sdim  { "stl_c",	emit_loadstore, "stl_c",
2851218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2852218822Sdim  { "stq",	emit_loadstore, "stq",
2853218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2854218822Sdim  { "stq_c",	emit_loadstore, "stq_c",
2855218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2856218822Sdim  { "stq_u",	emit_loadstore, "stq_u",
2857218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2858218822Sdim  { "stf",	emit_loadstore, "stf",
2859218822Sdim    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2860218822Sdim  { "stg",	emit_loadstore, "stg",
2861218822Sdim    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2862218822Sdim  { "sts",	emit_loadstore, "sts",
2863218822Sdim    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2864218822Sdim  { "stt",	emit_loadstore, "stt",
2865218822Sdim    { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2866218822Sdim
2867218822Sdim  { "stb",	emit_stX, (void *) 0,
2868218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2869218822Sdim  { "stw",	emit_stX, (void *) 1,
2870218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2871218822Sdim  { "ustw",	emit_ustX, (void *) 1,
2872218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2873218822Sdim  { "ustl",	emit_ustX, (void *) 2,
2874218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2875218822Sdim  { "ustq",	emit_ustX, (void *) 3,
2876218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
2877218822Sdim
2878218822Sdim/* Arithmetic macros.  */
2879218822Sdim
2880218822Sdim  { "sextb",	emit_sextX, (void *) 0,
2881218822Sdim    { MACRO_IR, MACRO_IR, MACRO_EOA,
2882218822Sdim      MACRO_IR, MACRO_EOA,
2883218822Sdim      /* MACRO_EXP, MACRO_IR, MACRO_EOA */ } },
2884218822Sdim  { "sextw",	emit_sextX, (void *) 1,
2885218822Sdim    { MACRO_IR, MACRO_IR, MACRO_EOA,
2886218822Sdim      MACRO_IR, MACRO_EOA,
2887218822Sdim      /* MACRO_EXP, MACRO_IR, MACRO_EOA */ } },
2888218822Sdim
2889218822Sdim  { "divl",	emit_division, "__divl",
2890218822Sdim    { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
2891218822Sdim      MACRO_IR, MACRO_IR, MACRO_EOA,
2892218822Sdim      /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA,
2893218822Sdim      MACRO_IR, MACRO_EXP, MACRO_EOA */ } },
2894218822Sdim  { "divlu",	emit_division, "__divlu",
2895218822Sdim    { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
2896218822Sdim      MACRO_IR, MACRO_IR, MACRO_EOA,
2897218822Sdim      /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA,
2898218822Sdim      MACRO_IR, MACRO_EXP, MACRO_EOA */ } },
2899218822Sdim  { "divq",	emit_division, "__divq",
2900218822Sdim    { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
2901218822Sdim      MACRO_IR, MACRO_IR, MACRO_EOA,
2902218822Sdim      /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA,
2903218822Sdim      MACRO_IR, MACRO_EXP, MACRO_EOA */ } },
2904218822Sdim  { "divqu",	emit_division, "__divqu",
2905218822Sdim    { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
2906218822Sdim      MACRO_IR, MACRO_IR, MACRO_EOA,
2907218822Sdim      /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA,
2908218822Sdim      MACRO_IR, MACRO_EXP, MACRO_EOA */ } },
2909218822Sdim  { "reml",	emit_division, "__reml",
2910218822Sdim    { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
2911218822Sdim      MACRO_IR, MACRO_IR, MACRO_EOA,
2912218822Sdim      /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA,
2913218822Sdim      MACRO_IR, MACRO_EXP, MACRO_EOA */ } },
2914218822Sdim  { "remlu",	emit_division, "__remlu",
2915218822Sdim    { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
2916218822Sdim      MACRO_IR, MACRO_IR, MACRO_EOA,
2917218822Sdim      /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA,
2918218822Sdim      MACRO_IR, MACRO_EXP, MACRO_EOA */ } },
2919218822Sdim  { "remq",	emit_division, "__remq",
2920218822Sdim    { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
2921218822Sdim      MACRO_IR, MACRO_IR, MACRO_EOA,
2922218822Sdim      /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA,
2923218822Sdim      MACRO_IR, MACRO_EXP, MACRO_EOA */ } },
2924218822Sdim  { "remqu",	emit_division, "__remqu",
2925218822Sdim    { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
2926218822Sdim      MACRO_IR, MACRO_IR, MACRO_EOA,
2927218822Sdim      /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA,
2928218822Sdim      MACRO_IR, MACRO_EXP, MACRO_EOA */ } },
2929218822Sdim
2930218822Sdim  { "jsr",	emit_jsrjmp, "jsr",
2931218822Sdim    { MACRO_PIR, MACRO_EXP, MACRO_EOA,
2932218822Sdim      MACRO_PIR, MACRO_EOA,
2933218822Sdim      MACRO_IR,  MACRO_EXP, MACRO_EOA,
2934218822Sdim      MACRO_EXP, MACRO_EOA } },
2935218822Sdim  { "jmp",	emit_jsrjmp, "jmp",
2936218822Sdim    { MACRO_PIR, MACRO_EXP, MACRO_EOA,
2937218822Sdim      MACRO_PIR, MACRO_EOA,
2938218822Sdim      MACRO_IR,  MACRO_EXP, MACRO_EOA,
2939218822Sdim      MACRO_EXP, MACRO_EOA } },
2940218822Sdim  { "ret",	emit_retjcr, "ret",
2941218822Sdim    { MACRO_IR, MACRO_EXP, MACRO_EOA,
2942218822Sdim      MACRO_IR, MACRO_EOA,
2943218822Sdim      MACRO_PIR, MACRO_EXP, MACRO_EOA,
2944218822Sdim      MACRO_PIR, MACRO_EOA,
2945218822Sdim      MACRO_EXP, MACRO_EOA,
2946218822Sdim      MACRO_EOA } },
2947218822Sdim  { "jcr",	emit_retjcr, "jcr",
2948218822Sdim    { MACRO_IR,  MACRO_EXP, MACRO_EOA,
2949218822Sdim      MACRO_IR,  MACRO_EOA,
2950218822Sdim      MACRO_PIR, MACRO_EXP, MACRO_EOA,
2951218822Sdim      MACRO_PIR, MACRO_EOA,
2952218822Sdim      MACRO_EXP, MACRO_EOA,
2953218822Sdim      MACRO_EOA } },
2954218822Sdim  { "jsr_coroutine",	emit_retjcr, "jcr",
2955218822Sdim    { MACRO_IR,  MACRO_EXP, MACRO_EOA,
2956218822Sdim      MACRO_IR,  MACRO_EOA,
2957218822Sdim      MACRO_PIR, MACRO_EXP, MACRO_EOA,
2958218822Sdim      MACRO_PIR, MACRO_EOA,
2959218822Sdim      MACRO_EXP, MACRO_EOA,
2960218822Sdim      MACRO_EOA } },
2961218822Sdim};
2962218822Sdim
2963218822Sdimstatic const unsigned int alpha_num_macros
2964218822Sdim  = sizeof (alpha_macros) / sizeof (*alpha_macros);
2965218822Sdim
2966218822Sdim/* Search forward through all variants of a macro looking for a syntax
2967218822Sdim   match.  */
2968218822Sdim
2969218822Sdimstatic const struct alpha_macro *
2970218822Sdimfind_macro_match (const struct alpha_macro *first_macro,
2971218822Sdim		  const expressionS *tok,
2972218822Sdim		  int *pntok)
2973218822Sdim
2974218822Sdim{
2975218822Sdim  const struct alpha_macro *macro = first_macro;
2976218822Sdim  int ntok = *pntok;
2977218822Sdim
2978218822Sdim  do
2979218822Sdim    {
2980218822Sdim      const enum alpha_macro_arg *arg = macro->argsets;
2981218822Sdim      int tokidx = 0;
2982218822Sdim
2983218822Sdim      while (*arg)
2984218822Sdim	{
2985218822Sdim	  switch (*arg)
2986218822Sdim	    {
2987218822Sdim	    case MACRO_EOA:
2988218822Sdim	      if (tokidx == ntok)
2989218822Sdim		return macro;
2990218822Sdim	      else
2991218822Sdim		tokidx = 0;
2992218822Sdim	      break;
2993218822Sdim
2994218822Sdim	      /* Index register.  */
2995218822Sdim	    case MACRO_IR:
2996218822Sdim	      if (tokidx >= ntok || tok[tokidx].X_op != O_register
2997218822Sdim		  || !is_ir_num (tok[tokidx].X_add_number))
2998218822Sdim		goto match_failed;
2999218822Sdim	      ++tokidx;
3000218822Sdim	      break;
3001218822Sdim
3002218822Sdim	      /* Parenthesized index register.  */
3003218822Sdim	    case MACRO_PIR:
3004218822Sdim	      if (tokidx >= ntok || tok[tokidx].X_op != O_pregister
3005218822Sdim		  || !is_ir_num (tok[tokidx].X_add_number))
3006218822Sdim		goto match_failed;
3007218822Sdim	      ++tokidx;
3008218822Sdim	      break;
3009218822Sdim
3010218822Sdim	      /* Optional parenthesized index register.  */
3011218822Sdim	    case MACRO_OPIR:
3012218822Sdim	      if (tokidx < ntok && tok[tokidx].X_op == O_pregister
3013218822Sdim		  && is_ir_num (tok[tokidx].X_add_number))
3014218822Sdim		++tokidx;
3015218822Sdim	      break;
3016218822Sdim
3017218822Sdim	      /* Leading comma with a parenthesized index register.  */
3018218822Sdim	    case MACRO_CPIR:
3019218822Sdim	      if (tokidx >= ntok || tok[tokidx].X_op != O_cpregister
3020218822Sdim		  || !is_ir_num (tok[tokidx].X_add_number))
3021218822Sdim		goto match_failed;
3022218822Sdim	      ++tokidx;
3023218822Sdim	      break;
3024218822Sdim
3025218822Sdim	      /* Floating point register.  */
3026218822Sdim	    case MACRO_FPR:
3027218822Sdim	      if (tokidx >= ntok || tok[tokidx].X_op != O_register
3028218822Sdim		  || !is_fpr_num (tok[tokidx].X_add_number))
3029218822Sdim		goto match_failed;
3030218822Sdim	      ++tokidx;
3031218822Sdim	      break;
3032218822Sdim
3033218822Sdim	      /* Normal expression.  */
3034218822Sdim	    case MACRO_EXP:
3035218822Sdim	      if (tokidx >= ntok)
3036218822Sdim		goto match_failed;
3037218822Sdim	      switch (tok[tokidx].X_op)
3038218822Sdim		{
3039218822Sdim		case O_illegal:
3040218822Sdim		case O_absent:
3041218822Sdim		case O_register:
3042218822Sdim		case O_pregister:
3043218822Sdim		case O_cpregister:
3044218822Sdim		case O_literal:
3045218822Sdim		case O_lituse_base:
3046218822Sdim		case O_lituse_bytoff:
3047218822Sdim		case O_lituse_jsr:
3048218822Sdim		case O_gpdisp:
3049218822Sdim		case O_gprelhigh:
3050218822Sdim		case O_gprellow:
3051218822Sdim		case O_gprel:
3052218822Sdim		case O_samegp:
3053218822Sdim		  goto match_failed;
3054218822Sdim
3055218822Sdim		default:
3056218822Sdim		  break;
3057218822Sdim		}
3058218822Sdim	      ++tokidx;
3059218822Sdim	      break;
3060218822Sdim
3061218822Sdim	    match_failed:
3062218822Sdim	      while (*arg != MACRO_EOA)
3063218822Sdim		++arg;
3064218822Sdim	      tokidx = 0;
3065218822Sdim	      break;
3066218822Sdim	    }
3067218822Sdim	  ++arg;
3068218822Sdim	}
3069218822Sdim    }
3070218822Sdim  while (++macro - alpha_macros < (int) alpha_num_macros
3071218822Sdim	 && !strcmp (macro->name, first_macro->name));
3072218822Sdim
3073218822Sdim  return NULL;
3074218822Sdim}
3075218822Sdim
3076218822Sdim/* Given an opcode name and a pre-tokenized set of arguments, take the
3077218822Sdim   opcode all the way through emission.  */
3078218822Sdim
3079218822Sdimstatic void
3080218822Sdimassemble_tokens (const char *opname,
3081218822Sdim		 const expressionS *tok,
3082218822Sdim		 int ntok,
3083218822Sdim		 int local_macros_on)
3084218822Sdim{
3085218822Sdim  int found_something = 0;
3086218822Sdim  const struct alpha_opcode *opcode;
3087218822Sdim  const struct alpha_macro *macro;
3088218822Sdim  int cpumatch = 1;
3089218822Sdim  bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
3090218822Sdim
3091218822Sdim#ifdef RELOC_OP_P
3092218822Sdim  /* If a user-specified relocation is present, this is not a macro.  */
3093218822Sdim  if (ntok && USER_RELOC_P (tok[ntok - 1].X_op))
3094218822Sdim    {
3095218822Sdim      reloc = ALPHA_RELOC_TABLE (tok[ntok - 1].X_op)->reloc;
3096218822Sdim      ntok--;
3097218822Sdim    }
3098218822Sdim  else
3099218822Sdim#endif
3100218822Sdim  if (local_macros_on)
3101218822Sdim    {
3102218822Sdim      macro = ((const struct alpha_macro *)
3103218822Sdim	       hash_find (alpha_macro_hash, opname));
3104218822Sdim      if (macro)
3105218822Sdim	{
3106218822Sdim	  found_something = 1;
3107218822Sdim	  macro = find_macro_match (macro, tok, &ntok);
3108218822Sdim	  if (macro)
3109218822Sdim	    {
3110218822Sdim	      (*macro->emit) (tok, ntok, macro->arg);
3111218822Sdim	      return;
3112218822Sdim	    }
3113218822Sdim	}
3114218822Sdim    }
3115218822Sdim
3116218822Sdim  /* Search opcodes.  */
3117218822Sdim  opcode = (const struct alpha_opcode *) hash_find (alpha_opcode_hash, opname);
3118218822Sdim  if (opcode)
3119218822Sdim    {
3120218822Sdim      found_something = 1;
3121218822Sdim      opcode = find_opcode_match (opcode, tok, &ntok, &cpumatch);
3122218822Sdim      if (opcode)
3123218822Sdim	{
3124218822Sdim	  struct alpha_insn insn;
3125218822Sdim	  assemble_insn (opcode, tok, ntok, &insn, reloc);
3126218822Sdim
3127218822Sdim	  /* Copy the sequence number for the reloc from the reloc token.  */
3128218822Sdim	  if (reloc != BFD_RELOC_UNUSED)
3129218822Sdim	    insn.sequence = tok[ntok].X_add_number;
3130218822Sdim
3131218822Sdim	  emit_insn (&insn);
3132218822Sdim	  return;
3133218822Sdim	}
3134218822Sdim    }
3135218822Sdim
3136218822Sdim  if (found_something)
3137218822Sdim    {
3138218822Sdim      if (cpumatch)
3139218822Sdim	as_bad (_("inappropriate arguments for opcode `%s'"), opname);
3140218822Sdim      else
3141218822Sdim	as_bad (_("opcode `%s' not supported for target %s"), opname,
3142218822Sdim		alpha_target_name);
3143218822Sdim    }
3144218822Sdim  else
3145218822Sdim    as_bad (_("unknown opcode `%s'"), opname);
3146218822Sdim}
314733965Sjdp
3148218822Sdim#ifdef OBJ_EVAX
3149218822Sdim
3150218822Sdim/* Add symbol+addend to link pool.
3151218822Sdim   Return offset from basesym to entry in link pool.
3152218822Sdim
3153218822Sdim   Add new fixup only if offset isn't 16bit.  */
3154218822Sdim
3155218822SdimvalueT
3156218822Sdimadd_to_link_pool (symbolS *basesym,
3157218822Sdim		  symbolS *sym,
3158218822Sdim		  offsetT addend)
3159218822Sdim{
3160218822Sdim  segT current_section = now_seg;
3161218822Sdim  int current_subsec = now_subseg;
3162218822Sdim  valueT offset;
3163218822Sdim  bfd_reloc_code_real_type reloc_type;
3164218822Sdim  char *p;
3165218822Sdim  segment_info_type *seginfo = seg_info (alpha_link_section);
3166218822Sdim  fixS *fixp;
3167218822Sdim
3168218822Sdim  offset = - *symbol_get_obj (basesym);
3169218822Sdim
3170218822Sdim  /* @@ This assumes all entries in a given section will be of the same
3171218822Sdim     size...  Probably correct, but unwise to rely on.  */
3172218822Sdim  /* This must always be called with the same subsegment.  */
3173218822Sdim
3174218822Sdim  if (seginfo->frchainP)
3175218822Sdim    for (fixp = seginfo->frchainP->fix_root;
3176218822Sdim	 fixp != (fixS *) NULL;
3177218822Sdim	 fixp = fixp->fx_next, offset += 8)
3178218822Sdim      {
3179218822Sdim	if (fixp->fx_addsy == sym && fixp->fx_offset == addend)
3180218822Sdim	  {
3181218822Sdim	    if (range_signed_16 (offset))
3182218822Sdim	      {
3183218822Sdim		return offset;
3184218822Sdim	      }
3185218822Sdim	  }
3186218822Sdim      }
3187218822Sdim
3188218822Sdim  /* Not found in 16bit signed range.  */
3189218822Sdim
3190218822Sdim  subseg_set (alpha_link_section, 0);
3191218822Sdim  p = frag_more (8);
3192218822Sdim  memset (p, 0, 8);
3193218822Sdim
3194218822Sdim  fix_new (frag_now, p - frag_now->fr_literal, 8, sym, addend, 0,
3195218822Sdim	   BFD_RELOC_64);
3196218822Sdim
3197218822Sdim  subseg_set (current_section, current_subsec);
3198218822Sdim  seginfo->literal_pool_size += 8;
3199218822Sdim  return offset;
3200218822Sdim}
3201218822Sdim
3202218822Sdim#endif /* OBJ_EVAX */
3203218822Sdim
3204130561Sobrien/* Assembler directives.  */
320533965Sjdp
320633965Sjdp/* Handle the .text pseudo-op.  This is like the usual one, but it
320733965Sjdp   clears alpha_insn_label and restores auto alignment.  */
320833965Sjdp
320933965Sjdpstatic void
3210218822Sdims_alpha_text (int i)
321133965Sjdp
321233965Sjdp{
321392828Sobrien#ifdef OBJ_ELF
321492828Sobrien  obj_elf_text (i);
321592828Sobrien#else
321633965Sjdp  s_text (i);
321792828Sobrien#endif
321833965Sjdp  alpha_insn_label = NULL;
321933965Sjdp  alpha_auto_align_on = 1;
322033965Sjdp  alpha_current_align = 0;
322133965Sjdp}
322233965Sjdp
322333965Sjdp/* Handle the .data pseudo-op.  This is like the usual one, but it
322433965Sjdp   clears alpha_insn_label and restores auto alignment.  */
322533965Sjdp
322633965Sjdpstatic void
3227218822Sdims_alpha_data (int i)
322833965Sjdp{
322992828Sobrien#ifdef OBJ_ELF
323092828Sobrien  obj_elf_data (i);
323192828Sobrien#else
323233965Sjdp  s_data (i);
323392828Sobrien#endif
323433965Sjdp  alpha_insn_label = NULL;
323533965Sjdp  alpha_auto_align_on = 1;
323633965Sjdp  alpha_current_align = 0;
323733965Sjdp}
323833965Sjdp
323938889Sjdp#if defined (OBJ_ECOFF) || defined (OBJ_EVAX)
324033965Sjdp
324138889Sjdp/* Handle the OSF/1 and openVMS .comm pseudo quirks.
324238889Sjdp   openVMS constructs a section for every common symbol.  */
324333965Sjdp
324433965Sjdpstatic void
3245218822Sdims_alpha_comm (int ignore ATTRIBUTE_UNUSED)
324633965Sjdp{
3247218822Sdim  char *name;
3248218822Sdim  char c;
3249218822Sdim  char *p;
325033965Sjdp  offsetT temp;
3251218822Sdim  symbolS *symbolP;
325238889Sjdp#ifdef OBJ_EVAX
325338889Sjdp  segT current_section = now_seg;
325438889Sjdp  int current_subsec = now_subseg;
325538889Sjdp  segT new_seg;
325638889Sjdp#endif
325738889Sjdp
325833965Sjdp  name = input_line_pointer;
325933965Sjdp  c = get_symbol_end ();
326033965Sjdp
3261218822Sdim  /* Just after name is now '\0'.  */
326233965Sjdp  p = input_line_pointer;
326333965Sjdp  *p = c;
326433965Sjdp
326533965Sjdp  SKIP_WHITESPACE ();
326633965Sjdp
326733965Sjdp  /* Alpha OSF/1 compiler doesn't provide the comma, gcc does.  */
326833965Sjdp  if (*input_line_pointer == ',')
326933965Sjdp    {
327033965Sjdp      input_line_pointer++;
327133965Sjdp      SKIP_WHITESPACE ();
327233965Sjdp    }
327333965Sjdp  if ((temp = get_absolute_expression ()) < 0)
327433965Sjdp    {
327560484Sobrien      as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) temp);
327633965Sjdp      ignore_rest_of_line ();
327733965Sjdp      return;
327833965Sjdp    }
327933965Sjdp
328033965Sjdp  *p = 0;
328133965Sjdp  symbolP = symbol_find_or_make (name);
328233965Sjdp
328338889Sjdp#ifdef OBJ_EVAX
328438889Sjdp  /* Make a section for the common symbol.  */
328538889Sjdp  new_seg = subseg_new (xstrdup (name), 0);
328638889Sjdp#endif
328738889Sjdp
328860484Sobrien  *p = c;
328960484Sobrien
329060484Sobrien#ifdef OBJ_EVAX
3291218822Sdim  /* Alignment might follow.  */
329260484Sobrien  if (*input_line_pointer == ',')
329360484Sobrien    {
329460484Sobrien      offsetT align;
329560484Sobrien
329677298Sobrien      input_line_pointer++;
329760484Sobrien      align = get_absolute_expression ();
329860484Sobrien      bfd_set_section_alignment (stdoutput, new_seg, align);
329960484Sobrien    }
330060484Sobrien#endif
330160484Sobrien
330233965Sjdp  if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
330333965Sjdp    {
330460484Sobrien      as_bad (_("Ignoring attempt to re-define symbol"));
330533965Sjdp      ignore_rest_of_line ();
330633965Sjdp      return;
330733965Sjdp    }
330833965Sjdp
330938889Sjdp#ifdef OBJ_EVAX
331038889Sjdp  if (bfd_section_size (stdoutput, new_seg) > 0)
331177298Sobrien    {
331238889Sjdp      if (bfd_section_size (stdoutput, new_seg) != temp)
331360484Sobrien	as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."),
331438889Sjdp		S_GET_NAME (symbolP),
331538889Sjdp		(long) bfd_section_size (stdoutput, new_seg),
331638889Sjdp		(long) temp);
331738889Sjdp    }
331838889Sjdp#else
331933965Sjdp  if (S_GET_VALUE (symbolP))
332033965Sjdp    {
332133965Sjdp      if (S_GET_VALUE (symbolP) != (valueT) temp)
332260484Sobrien	as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."),
332333965Sjdp		S_GET_NAME (symbolP),
332433965Sjdp		(long) S_GET_VALUE (symbolP),
332533965Sjdp		(long) temp);
332633965Sjdp    }
332738889Sjdp#endif
332833965Sjdp  else
332933965Sjdp    {
333077298Sobrien#ifdef OBJ_EVAX
333138889Sjdp      subseg_set (new_seg, 0);
333238889Sjdp      p = frag_more (temp);
333338889Sjdp      new_seg->flags |= SEC_IS_COMMON;
3334218822Sdim      S_SET_SEGMENT (symbolP, new_seg);
333538889Sjdp#else
333633965Sjdp      S_SET_VALUE (symbolP, (valueT) temp);
3337218822Sdim      S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
333838889Sjdp#endif
333933965Sjdp      S_SET_EXTERNAL (symbolP);
334033965Sjdp    }
334133965Sjdp
334238889Sjdp#ifdef OBJ_EVAX
334338889Sjdp  subseg_set (current_section, current_subsec);
334438889Sjdp#endif
334538889Sjdp
334660484Sobrien  know (symbol_get_frag (symbolP) == &zero_address_frag);
334733965Sjdp
334833965Sjdp  demand_empty_rest_of_line ();
334933965Sjdp}
335033965Sjdp
335133965Sjdp#endif /* ! OBJ_ELF */
335233965Sjdp
335333965Sjdp#ifdef OBJ_ECOFF
335433965Sjdp
335533965Sjdp/* Handle the .rdata pseudo-op.  This is like the usual one, but it
335633965Sjdp   clears alpha_insn_label and restores auto alignment.  */
335733965Sjdp
335833965Sjdpstatic void
3359218822Sdims_alpha_rdata (int ignore ATTRIBUTE_UNUSED)
336033965Sjdp{
336133965Sjdp  int temp;
336233965Sjdp
336333965Sjdp  temp = get_absolute_expression ();
336433965Sjdp  subseg_new (".rdata", 0);
336533965Sjdp  demand_empty_rest_of_line ();
336633965Sjdp  alpha_insn_label = NULL;
336733965Sjdp  alpha_auto_align_on = 1;
336833965Sjdp  alpha_current_align = 0;
336933965Sjdp}
337033965Sjdp
337133965Sjdp#endif
337233965Sjdp
337333965Sjdp#ifdef OBJ_ECOFF
337433965Sjdp
337533965Sjdp/* Handle the .sdata pseudo-op.  This is like the usual one, but it
337633965Sjdp   clears alpha_insn_label and restores auto alignment.  */
337733965Sjdp
337833965Sjdpstatic void
3379218822Sdims_alpha_sdata (int ignore ATTRIBUTE_UNUSED)
338033965Sjdp{
338133965Sjdp  int temp;
338233965Sjdp
338333965Sjdp  temp = get_absolute_expression ();
338433965Sjdp  subseg_new (".sdata", 0);
338533965Sjdp  demand_empty_rest_of_line ();
338633965Sjdp  alpha_insn_label = NULL;
338733965Sjdp  alpha_auto_align_on = 1;
338833965Sjdp  alpha_current_align = 0;
338933965Sjdp}
339033965Sjdp#endif
339133965Sjdp
339233965Sjdp#ifdef OBJ_ELF
3393130561Sobrienstruct alpha_elf_frame_data
3394130561Sobrien{
3395130561Sobrien  symbolS *func_sym;
3396130561Sobrien  symbolS *func_end_sym;
3397130561Sobrien  symbolS *prologue_sym;
3398130561Sobrien  unsigned int mask;
3399130561Sobrien  unsigned int fmask;
3400130561Sobrien  int fp_regno;
3401130561Sobrien  int ra_regno;
3402130561Sobrien  offsetT frame_size;
3403130561Sobrien  offsetT mask_offset;
3404130561Sobrien  offsetT fmask_offset;
340533965Sjdp
3406130561Sobrien  struct alpha_elf_frame_data *next;
3407130561Sobrien};
3408130561Sobrien
3409130561Sobrienstatic struct alpha_elf_frame_data *all_frame_data;
3410130561Sobrienstatic struct alpha_elf_frame_data **plast_frame_data = &all_frame_data;
3411130561Sobrienstatic struct alpha_elf_frame_data *cur_frame_data;
3412130561Sobrien
341333965Sjdp/* Handle the .section pseudo-op.  This is like the usual one, but it
341433965Sjdp   clears alpha_insn_label and restores auto alignment.  */
341533965Sjdp
341633965Sjdpstatic void
3417218822Sdims_alpha_section (int ignore ATTRIBUTE_UNUSED)
341833965Sjdp{
341933965Sjdp  obj_elf_section (ignore);
342033965Sjdp
342133965Sjdp  alpha_insn_label = NULL;
342233965Sjdp  alpha_auto_align_on = 1;
342333965Sjdp  alpha_current_align = 0;
342433965Sjdp}
342533965Sjdp
342660484Sobrienstatic void
3427218822Sdims_alpha_ent (int dummy ATTRIBUTE_UNUSED)
342860484Sobrien{
342960484Sobrien  if (ECOFF_DEBUGGING)
343060484Sobrien    ecoff_directive_ent (0);
343160484Sobrien  else
343260484Sobrien    {
343360484Sobrien      char *name, name_end;
343460484Sobrien      name = input_line_pointer;
343560484Sobrien      name_end = get_symbol_end ();
343633965Sjdp
343760484Sobrien      if (! is_name_beginner (*name))
343860484Sobrien	{
343960484Sobrien	  as_warn (_(".ent directive has no name"));
344060484Sobrien	  *input_line_pointer = name_end;
344160484Sobrien	}
344260484Sobrien      else
344360484Sobrien	{
344460484Sobrien	  symbolS *sym;
344560484Sobrien
3446130561Sobrien	  if (cur_frame_data)
344760484Sobrien	    as_warn (_("nested .ent directives"));
344860484Sobrien
344960484Sobrien	  sym = symbol_find_or_make (name);
345060484Sobrien	  symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
345160484Sobrien
3452130561Sobrien	  cur_frame_data = calloc (1, sizeof (*cur_frame_data));
3453130561Sobrien	  cur_frame_data->func_sym = sym;
3454130561Sobrien
3455130561Sobrien	  /* Provide sensible defaults.  */
3456130561Sobrien	  cur_frame_data->fp_regno = 30;	/* sp */
3457130561Sobrien	  cur_frame_data->ra_regno = 26;	/* ra */
3458130561Sobrien
3459130561Sobrien	  *plast_frame_data = cur_frame_data;
3460130561Sobrien	  plast_frame_data = &cur_frame_data->next;
3461130561Sobrien
346260484Sobrien	  /* The .ent directive is sometimes followed by a number.  Not sure
346360484Sobrien	     what it really means, but ignore it.  */
346460484Sobrien	  *input_line_pointer = name_end;
346560484Sobrien	  SKIP_WHITESPACE ();
346660484Sobrien	  if (*input_line_pointer == ',')
346760484Sobrien	    {
346860484Sobrien	      input_line_pointer++;
346960484Sobrien	      SKIP_WHITESPACE ();
347060484Sobrien	    }
347189857Sobrien	  if (ISDIGIT (*input_line_pointer) || *input_line_pointer == '-')
347260484Sobrien	    (void) get_absolute_expression ();
347360484Sobrien	}
347460484Sobrien      demand_empty_rest_of_line ();
347560484Sobrien    }
347660484Sobrien}
347760484Sobrien
347860484Sobrienstatic void
3479218822Sdims_alpha_end (int dummy ATTRIBUTE_UNUSED)
348060484Sobrien{
348160484Sobrien  if (ECOFF_DEBUGGING)
348260484Sobrien    ecoff_directive_end (0);
348360484Sobrien  else
348460484Sobrien    {
348560484Sobrien      char *name, name_end;
348660484Sobrien      name = input_line_pointer;
348760484Sobrien      name_end = get_symbol_end ();
348860484Sobrien
348960484Sobrien      if (! is_name_beginner (*name))
349060484Sobrien	{
349160484Sobrien	  as_warn (_(".end directive has no name"));
349260484Sobrien	  *input_line_pointer = name_end;
349360484Sobrien	}
349460484Sobrien      else
349560484Sobrien	{
349660484Sobrien	  symbolS *sym;
349760484Sobrien
349860484Sobrien	  sym = symbol_find (name);
3499130561Sobrien	  if (!cur_frame_data)
3500130561Sobrien	    as_warn (_(".end directive without matching .ent"));
3501130561Sobrien	  else if (sym != cur_frame_data->func_sym)
350260484Sobrien	    as_warn (_(".end directive names different symbol than .ent"));
350360484Sobrien
350460484Sobrien	  /* Create an expression to calculate the size of the function.  */
3505130561Sobrien	  if (sym && cur_frame_data)
350660484Sobrien	    {
3507130561Sobrien	      OBJ_SYMFIELD_TYPE *obj = symbol_get_obj (sym);
3508130561Sobrien	      expressionS *exp = xmalloc (sizeof (expressionS));
3509130561Sobrien
3510130561Sobrien	      obj->size = exp;
3511130561Sobrien	      exp->X_op = O_subtract;
3512130561Sobrien	      exp->X_add_symbol = symbol_temp_new_now ();
3513130561Sobrien	      exp->X_op_symbol = sym;
3514130561Sobrien	      exp->X_add_number = 0;
3515130561Sobrien
3516130561Sobrien	      cur_frame_data->func_end_sym = exp->X_add_symbol;
351760484Sobrien	    }
351860484Sobrien
3519130561Sobrien	  cur_frame_data = NULL;
352060484Sobrien
352160484Sobrien	  *input_line_pointer = name_end;
352260484Sobrien	}
352360484Sobrien      demand_empty_rest_of_line ();
352460484Sobrien    }
352560484Sobrien}
352660484Sobrien
352760484Sobrienstatic void
3528218822Sdims_alpha_mask (int fp)
352960484Sobrien{
353060484Sobrien  if (ECOFF_DEBUGGING)
353160484Sobrien    {
353260484Sobrien      if (fp)
353377298Sobrien	ecoff_directive_fmask (0);
353460484Sobrien      else
353577298Sobrien	ecoff_directive_mask (0);
353660484Sobrien    }
353760484Sobrien  else
3538130561Sobrien    {
3539130561Sobrien      long val;
3540130561Sobrien      offsetT offset;
3541130561Sobrien
3542130561Sobrien      if (!cur_frame_data)
3543130561Sobrien	{
3544130561Sobrien	  if (fp)
3545130561Sobrien	    as_warn (_(".fmask outside of .ent"));
3546130561Sobrien	  else
3547130561Sobrien	    as_warn (_(".mask outside of .ent"));
3548130561Sobrien	  discard_rest_of_line ();
3549130561Sobrien	  return;
3550130561Sobrien	}
3551130561Sobrien
3552130561Sobrien      if (get_absolute_expression_and_terminator (&val) != ',')
3553130561Sobrien	{
3554130561Sobrien	  if (fp)
3555130561Sobrien	    as_warn (_("bad .fmask directive"));
3556130561Sobrien	  else
3557130561Sobrien	    as_warn (_("bad .mask directive"));
3558130561Sobrien	  --input_line_pointer;
3559130561Sobrien	  discard_rest_of_line ();
3560130561Sobrien	  return;
3561130561Sobrien	}
3562130561Sobrien
3563130561Sobrien      offset = get_absolute_expression ();
3564130561Sobrien      demand_empty_rest_of_line ();
3565130561Sobrien
3566130561Sobrien      if (fp)
3567130561Sobrien	{
3568130561Sobrien	  cur_frame_data->fmask = val;
3569130561Sobrien          cur_frame_data->fmask_offset = offset;
3570130561Sobrien	}
3571130561Sobrien      else
3572130561Sobrien	{
3573130561Sobrien	  cur_frame_data->mask = val;
3574130561Sobrien	  cur_frame_data->mask_offset = offset;
3575130561Sobrien	}
3576130561Sobrien    }
357760484Sobrien}
357860484Sobrien
357960484Sobrienstatic void
3580218822Sdims_alpha_frame (int dummy ATTRIBUTE_UNUSED)
358160484Sobrien{
358260484Sobrien  if (ECOFF_DEBUGGING)
358360484Sobrien    ecoff_directive_frame (0);
358460484Sobrien  else
3585130561Sobrien    {
3586130561Sobrien      long val;
3587130561Sobrien
3588130561Sobrien      if (!cur_frame_data)
3589130561Sobrien	{
3590130561Sobrien	  as_warn (_(".frame outside of .ent"));
3591130561Sobrien	  discard_rest_of_line ();
3592130561Sobrien	  return;
3593130561Sobrien	}
3594130561Sobrien
3595130561Sobrien      cur_frame_data->fp_regno = tc_get_register (1);
3596130561Sobrien
3597130561Sobrien      SKIP_WHITESPACE ();
3598130561Sobrien      if (*input_line_pointer++ != ','
3599130561Sobrien	  || get_absolute_expression_and_terminator (&val) != ',')
3600130561Sobrien	{
3601130561Sobrien	  as_warn (_("bad .frame directive"));
3602130561Sobrien	  --input_line_pointer;
3603130561Sobrien	  discard_rest_of_line ();
3604130561Sobrien	  return;
3605130561Sobrien	}
3606130561Sobrien      cur_frame_data->frame_size = val;
3607130561Sobrien
3608130561Sobrien      cur_frame_data->ra_regno = tc_get_register (0);
3609130561Sobrien
3610130561Sobrien      /* Next comes the "offset of saved $a0 from $sp".  In gcc terms
3611130561Sobrien	 this is current_function_pretend_args_size.  There's no place
3612130561Sobrien	 to put this value, so ignore it.  */
3613130561Sobrien      s_ignore (42);
3614130561Sobrien    }
361560484Sobrien}
361660484Sobrien
361760484Sobrienstatic void
3618218822Sdims_alpha_prologue (int ignore ATTRIBUTE_UNUSED)
361960484Sobrien{
362060484Sobrien  symbolS *sym;
362160484Sobrien  int arg;
362260484Sobrien
362360484Sobrien  arg = get_absolute_expression ();
362460484Sobrien  demand_empty_rest_of_line ();
362560484Sobrien
362660484Sobrien  if (ECOFF_DEBUGGING)
362760484Sobrien    sym = ecoff_get_cur_proc_sym ();
362860484Sobrien  else
3629130561Sobrien    sym = cur_frame_data ? cur_frame_data->func_sym : NULL;
363060484Sobrien
3631107492Sobrien  if (sym == NULL)
3632107492Sobrien    {
3633107492Sobrien      as_bad (_(".prologue directive without a preceding .ent directive"));
3634107492Sobrien      return;
3635107492Sobrien    }
3636107492Sobrien
363760484Sobrien  switch (arg)
363860484Sobrien    {
363977298Sobrien    case 0: /* No PV required.  */
364077298Sobrien      S_SET_OTHER (sym, STO_ALPHA_NOPV
364177298Sobrien		   | (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD));
364277298Sobrien      break;
364377298Sobrien    case 1: /* Std GP load.  */
364477298Sobrien      S_SET_OTHER (sym, STO_ALPHA_STD_GPLOAD
364577298Sobrien		   | (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD));
364677298Sobrien      break;
364777298Sobrien    case 2: /* Non-std use of PV.  */
364877298Sobrien      break;
364960484Sobrien
365077298Sobrien    default:
365177298Sobrien      as_bad (_("Invalid argument %d to .prologue."), arg);
365277298Sobrien      break;
365377298Sobrien    }
3654130561Sobrien
3655130561Sobrien  if (cur_frame_data)
3656130561Sobrien    cur_frame_data->prologue_sym = symbol_temp_new_now ();
365760484Sobrien}
365860484Sobrien
365977298Sobrienstatic char *first_file_directive;
366077298Sobrien
366160484Sobrienstatic void
3662218822Sdims_alpha_file (int ignore ATTRIBUTE_UNUSED)
366377298Sobrien{
366477298Sobrien  /* Save the first .file directive we see, so that we can change our
366577298Sobrien     minds about whether ecoff debugging should or shouldn't be enabled.  */
366677298Sobrien  if (alpha_flag_mdebug < 0 && ! first_file_directive)
366777298Sobrien    {
366877298Sobrien      char *start = input_line_pointer;
366977298Sobrien      size_t len;
367077298Sobrien
367177298Sobrien      discard_rest_of_line ();
367277298Sobrien
367377298Sobrien      len = input_line_pointer - start;
367477298Sobrien      first_file_directive = xmalloc (len + 1);
367577298Sobrien      memcpy (first_file_directive, start, len);
367677298Sobrien      first_file_directive[len] = '\0';
367777298Sobrien
367877298Sobrien      input_line_pointer = start;
367977298Sobrien    }
368077298Sobrien
368177298Sobrien  if (ECOFF_DEBUGGING)
368277298Sobrien    ecoff_directive_file (0);
368377298Sobrien  else
368477298Sobrien    dwarf2_directive_file (0);
368577298Sobrien}
368677298Sobrien
368777298Sobrienstatic void
3688218822Sdims_alpha_loc (int ignore ATTRIBUTE_UNUSED)
368977298Sobrien{
369077298Sobrien  if (ECOFF_DEBUGGING)
369177298Sobrien    ecoff_directive_loc (0);
369277298Sobrien  else
369377298Sobrien    dwarf2_directive_loc (0);
369477298Sobrien}
369577298Sobrien
369677298Sobrienstatic void
3697218822Sdims_alpha_stab (int n)
369877298Sobrien{
369977298Sobrien  /* If we've been undecided about mdebug, make up our minds in favour.  */
370077298Sobrien  if (alpha_flag_mdebug < 0)
370177298Sobrien    {
370277298Sobrien      segT sec = subseg_new (".mdebug", 0);
370377298Sobrien      bfd_set_section_flags (stdoutput, sec, SEC_HAS_CONTENTS | SEC_READONLY);
370477298Sobrien      bfd_set_section_alignment (stdoutput, sec, 3);
370577298Sobrien
370677298Sobrien      ecoff_read_begin_hook ();
370777298Sobrien
370877298Sobrien      if (first_file_directive)
370977298Sobrien	{
371077298Sobrien	  char *save_ilp = input_line_pointer;
371177298Sobrien	  input_line_pointer = first_file_directive;
371277298Sobrien	  ecoff_directive_file (0);
371377298Sobrien	  input_line_pointer = save_ilp;
371477298Sobrien	  free (first_file_directive);
371577298Sobrien	}
371677298Sobrien
371777298Sobrien      alpha_flag_mdebug = 1;
371877298Sobrien    }
371977298Sobrien  s_stab (n);
372077298Sobrien}
372177298Sobrien
372277298Sobrienstatic void
3723218822Sdims_alpha_coff_wrapper (int which)
372460484Sobrien{
372560484Sobrien  static void (* const fns[]) PARAMS ((int)) = {
372660484Sobrien    ecoff_directive_begin,
372760484Sobrien    ecoff_directive_bend,
372860484Sobrien    ecoff_directive_def,
372960484Sobrien    ecoff_directive_dim,
373060484Sobrien    ecoff_directive_endef,
373160484Sobrien    ecoff_directive_scl,
373260484Sobrien    ecoff_directive_tag,
373360484Sobrien    ecoff_directive_val,
373460484Sobrien  };
373560484Sobrien
373677298Sobrien  assert (which >= 0 && which < (int) (sizeof (fns)/sizeof (*fns)));
373760484Sobrien
373860484Sobrien  if (ECOFF_DEBUGGING)
373977298Sobrien    (*fns[which]) (0);
374060484Sobrien  else
374160484Sobrien    {
374260484Sobrien      as_bad (_("ECOFF debugging is disabled."));
374360484Sobrien      ignore_rest_of_line ();
374460484Sobrien    }
374560484Sobrien}
3746130561Sobrien
3747130561Sobrien/* Called at the end of assembly.  Here we emit unwind info for frames
3748130561Sobrien   unless the compiler has done it for us.  */
3749130561Sobrien
3750130561Sobrienvoid
3751130561Sobrienalpha_elf_md_end (void)
3752130561Sobrien{
3753130561Sobrien  struct alpha_elf_frame_data *p;
3754130561Sobrien
3755130561Sobrien  if (cur_frame_data)
3756130561Sobrien    as_warn (_(".ent directive without matching .end"));
3757130561Sobrien
3758130561Sobrien  /* If someone has generated the unwind info themselves, great.  */
3759130561Sobrien  if (bfd_get_section_by_name (stdoutput, ".eh_frame") != NULL)
3760130561Sobrien    return;
3761130561Sobrien
3762130561Sobrien  /* Generate .eh_frame data for the unwind directives specified.  */
3763130561Sobrien  for (p = all_frame_data; p ; p = p->next)
3764130561Sobrien    if (p->prologue_sym)
3765130561Sobrien      {
3766130561Sobrien	/* Create a temporary symbol at the same location as our
3767130561Sobrien	   function symbol.  This prevents problems with globals.  */
3768130561Sobrien	cfi_new_fde (symbol_temp_new (S_GET_SEGMENT (p->func_sym),
3769130561Sobrien				      S_GET_VALUE (p->func_sym),
3770130561Sobrien				      symbol_get_frag (p->func_sym)));
3771130561Sobrien
3772130561Sobrien	cfi_set_return_column (p->ra_regno);
3773130561Sobrien	cfi_add_CFA_def_cfa_register (30);
3774130561Sobrien	if (p->fp_regno != 30 || p->mask || p->fmask || p->frame_size)
3775130561Sobrien	  {
3776130561Sobrien	    unsigned int mask;
3777130561Sobrien	    offsetT offset;
3778130561Sobrien
3779130561Sobrien	    cfi_add_advance_loc (p->prologue_sym);
3780130561Sobrien
3781130561Sobrien	    if (p->fp_regno != 30)
3782130561Sobrien	      if (p->frame_size != 0)
3783130561Sobrien		cfi_add_CFA_def_cfa (p->fp_regno, p->frame_size);
3784130561Sobrien	      else
3785130561Sobrien		cfi_add_CFA_def_cfa_register (p->fp_regno);
3786130561Sobrien	    else if (p->frame_size != 0)
3787130561Sobrien	      cfi_add_CFA_def_cfa_offset (p->frame_size);
3788130561Sobrien
3789130561Sobrien	    mask = p->mask;
3790130561Sobrien	    offset = p->mask_offset;
3791130561Sobrien
3792130561Sobrien	    /* Recall that $26 is special-cased and stored first.  */
3793130561Sobrien	    if ((mask >> 26) & 1)
3794130561Sobrien	      {
3795130561Sobrien	        cfi_add_CFA_offset (26, offset);
3796130561Sobrien		offset += 8;
3797130561Sobrien		mask &= ~(1 << 26);
3798130561Sobrien	      }
3799130561Sobrien	    while (mask)
3800130561Sobrien	      {
3801130561Sobrien		unsigned int i;
3802130561Sobrien		i = mask & -mask;
3803130561Sobrien		mask ^= i;
3804130561Sobrien		i = ffs (i) - 1;
3805130561Sobrien
3806130561Sobrien		cfi_add_CFA_offset (i, offset);
3807130561Sobrien		offset += 8;
3808130561Sobrien	      }
3809130561Sobrien
3810130561Sobrien	    mask = p->fmask;
3811130561Sobrien	    offset = p->fmask_offset;
3812130561Sobrien	    while (mask)
3813130561Sobrien	      {
3814130561Sobrien		unsigned int i;
3815130561Sobrien		i = mask & -mask;
3816130561Sobrien		mask ^= i;
3817130561Sobrien		i = ffs (i) - 1;
3818130561Sobrien
3819130561Sobrien		cfi_add_CFA_offset (i + 32, offset);
3820130561Sobrien		offset += 8;
3821130561Sobrien	      }
3822130561Sobrien	  }
3823130561Sobrien
3824130561Sobrien	cfi_end_fde (p->func_end_sym);
3825130561Sobrien      }
3826130561Sobrien}
3827130561Sobrien
3828130561Sobrienstatic void
3829130561Sobriens_alpha_usepv (int unused ATTRIBUTE_UNUSED)
3830130561Sobrien{
3831130561Sobrien  char *name, name_end;
3832130561Sobrien  char *which, which_end;
3833130561Sobrien  symbolS *sym;
3834130561Sobrien  int other;
3835130561Sobrien
3836130561Sobrien  name = input_line_pointer;
3837130561Sobrien  name_end = get_symbol_end ();
3838130561Sobrien
3839130561Sobrien  if (! is_name_beginner (*name))
3840130561Sobrien    {
3841130561Sobrien      as_bad (_(".usepv directive has no name"));
3842130561Sobrien      *input_line_pointer = name_end;
3843130561Sobrien      ignore_rest_of_line ();
3844130561Sobrien      return;
3845130561Sobrien    }
3846130561Sobrien
3847130561Sobrien  sym = symbol_find_or_make (name);
3848130561Sobrien  *input_line_pointer++ = name_end;
3849130561Sobrien
3850130561Sobrien  if (name_end != ',')
3851130561Sobrien    {
3852130561Sobrien      as_bad (_(".usepv directive has no type"));
3853130561Sobrien      ignore_rest_of_line ();
3854130561Sobrien      return;
3855130561Sobrien    }
3856130561Sobrien
3857130561Sobrien  SKIP_WHITESPACE ();
3858130561Sobrien  which = input_line_pointer;
3859130561Sobrien  which_end = get_symbol_end ();
3860130561Sobrien
3861130561Sobrien  if (strcmp (which, "no") == 0)
3862130561Sobrien    other = STO_ALPHA_NOPV;
3863130561Sobrien  else if (strcmp (which, "std") == 0)
3864130561Sobrien    other = STO_ALPHA_STD_GPLOAD;
3865130561Sobrien  else
3866130561Sobrien    {
3867130561Sobrien      as_bad (_("unknown argument for .usepv"));
3868130561Sobrien      other = 0;
3869130561Sobrien    }
3870218822Sdim
3871130561Sobrien  *input_line_pointer = which_end;
3872130561Sobrien  demand_empty_rest_of_line ();
3873130561Sobrien
3874130561Sobrien  S_SET_OTHER (sym, other | (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD));
3875130561Sobrien}
387660484Sobrien#endif /* OBJ_ELF */
387760484Sobrien
3878130561Sobrien/* Standard calling conventions leaves the CFA at $30 on entry.  */
3879130561Sobrien
3880130561Sobrienvoid
3881218822Sdimalpha_cfi_frame_initial_instructions (void)
3882130561Sobrien{
3883130561Sobrien  cfi_add_CFA_def_cfa_register (30);
3884130561Sobrien}
3885130561Sobrien
388633965Sjdp#ifdef OBJ_EVAX
388777298Sobrien
388833965Sjdp/* Handle the section specific pseudo-op.  */
388977298Sobrien
389033965Sjdpstatic void
3891218822Sdims_alpha_section (int secid)
389233965Sjdp{
389333965Sjdp  int temp;
389438889Sjdp#define EVAX_SECTION_COUNT 5
389577298Sobrien  static char *section_name[EVAX_SECTION_COUNT + 1] =
389638889Sjdp    { "NULL", ".rdata", ".comm", ".link", ".ctors", ".dtors" };
389733965Sjdp
389833965Sjdp  if ((secid <= 0) || (secid > EVAX_SECTION_COUNT))
389933965Sjdp    {
390060484Sobrien      as_fatal (_("Unknown section directive"));
390133965Sjdp      demand_empty_rest_of_line ();
390233965Sjdp      return;
390333965Sjdp    }
390433965Sjdp  temp = get_absolute_expression ();
390533965Sjdp  subseg_new (section_name[secid], 0);
390633965Sjdp  demand_empty_rest_of_line ();
390733965Sjdp  alpha_insn_label = NULL;
390833965Sjdp  alpha_auto_align_on = 1;
390933965Sjdp  alpha_current_align = 0;
391033965Sjdp}
391133965Sjdp
391233965Sjdp/* Parse .ent directives.  */
391333965Sjdp
391433965Sjdpstatic void
3915218822Sdims_alpha_ent (int ignore ATTRIBUTE_UNUSED)
391633965Sjdp{
391733965Sjdp  symbolS *symbol;
391833965Sjdp  expressionS symexpr;
391933965Sjdp
392033965Sjdp  alpha_evax_proc.pdsckind = 0;
392133965Sjdp  alpha_evax_proc.framereg = -1;
392233965Sjdp  alpha_evax_proc.framesize = 0;
392333965Sjdp  alpha_evax_proc.rsa_offset = 0;
392433965Sjdp  alpha_evax_proc.ra_save = AXP_REG_RA;
392533965Sjdp  alpha_evax_proc.fp_save = -1;
392633965Sjdp  alpha_evax_proc.imask = 0;
392733965Sjdp  alpha_evax_proc.fmask = 0;
392833965Sjdp  alpha_evax_proc.prologue = 0;
392933965Sjdp  alpha_evax_proc.type = 0;
393033965Sjdp
393133965Sjdp  expression (&symexpr);
393233965Sjdp
393333965Sjdp  if (symexpr.X_op != O_symbol)
393433965Sjdp    {
393560484Sobrien      as_fatal (_(".ent directive has no symbol"));
393633965Sjdp      demand_empty_rest_of_line ();
393733965Sjdp      return;
393833965Sjdp    }
393933965Sjdp
394033965Sjdp  symbol = make_expr_symbol (&symexpr);
394160484Sobrien  symbol_get_bfdsym (symbol)->flags |= BSF_FUNCTION;
394233965Sjdp  alpha_evax_proc.symbol = symbol;
394333965Sjdp
394433965Sjdp  demand_empty_rest_of_line ();
394533965Sjdp}
394633965Sjdp
394733965Sjdp/* Parse .frame <framreg>,<framesize>,RA,<rsa_offset> directives.  */
394833965Sjdp
394933965Sjdpstatic void
3950218822Sdims_alpha_frame (int ignore ATTRIBUTE_UNUSED)
395133965Sjdp{
395233965Sjdp  long val;
395333965Sjdp
395433965Sjdp  alpha_evax_proc.framereg = tc_get_register (1);
395533965Sjdp
395633965Sjdp  SKIP_WHITESPACE ();
395733965Sjdp  if (*input_line_pointer++ != ','
395833965Sjdp      || get_absolute_expression_and_terminator (&val) != ',')
395933965Sjdp    {
396060484Sobrien      as_warn (_("Bad .frame directive 1./2. param"));
396133965Sjdp      --input_line_pointer;
396233965Sjdp      demand_empty_rest_of_line ();
396333965Sjdp      return;
396433965Sjdp    }
396533965Sjdp
396633965Sjdp  alpha_evax_proc.framesize = val;
396733965Sjdp
396833965Sjdp  (void) tc_get_register (1);
396933965Sjdp  SKIP_WHITESPACE ();
397033965Sjdp  if (*input_line_pointer++ != ',')
397133965Sjdp    {
397260484Sobrien      as_warn (_("Bad .frame directive 3./4. param"));
397333965Sjdp      --input_line_pointer;
397433965Sjdp      demand_empty_rest_of_line ();
397533965Sjdp      return;
397633965Sjdp    }
397733965Sjdp  alpha_evax_proc.rsa_offset = get_absolute_expression ();
397833965Sjdp}
397933965Sjdp
398033965Sjdpstatic void
3981218822Sdims_alpha_pdesc (int ignore ATTRIBUTE_UNUSED)
398233965Sjdp{
398333965Sjdp  char *name;
398433965Sjdp  char name_end;
398533965Sjdp  long val;
398633965Sjdp  register char *p;
398733965Sjdp  expressionS exp;
398833965Sjdp  symbolS *entry_sym;
398933965Sjdp  fixS *fixp;
399033965Sjdp  segment_info_type *seginfo = seg_info (alpha_link_section);
399133965Sjdp
399233965Sjdp  if (now_seg != alpha_link_section)
399333965Sjdp    {
399460484Sobrien      as_bad (_(".pdesc directive not in link (.link) section"));
399533965Sjdp      demand_empty_rest_of_line ();
399633965Sjdp      return;
399733965Sjdp    }
399833965Sjdp
399933965Sjdp  if ((alpha_evax_proc.symbol == 0)
400033965Sjdp      || (!S_IS_DEFINED (alpha_evax_proc.symbol)))
400133965Sjdp    {
400260484Sobrien      as_fatal (_(".pdesc has no matching .ent"));
400333965Sjdp      demand_empty_rest_of_line ();
400433965Sjdp      return;
400533965Sjdp    }
400633965Sjdp
400760484Sobrien  *symbol_get_obj (alpha_evax_proc.symbol) =
400860484Sobrien    (valueT) seginfo->literal_pool_size;
400933965Sjdp
401033965Sjdp  expression (&exp);
401133965Sjdp  if (exp.X_op != O_symbol)
401233965Sjdp    {
401360484Sobrien      as_warn (_(".pdesc directive has no entry symbol"));
401433965Sjdp      demand_empty_rest_of_line ();
401533965Sjdp      return;
401633965Sjdp    }
401733965Sjdp
401833965Sjdp  entry_sym = make_expr_symbol (&exp);
401933965Sjdp  /* Save bfd symbol of proc desc in function symbol.  */
402060484Sobrien  symbol_get_bfdsym (alpha_evax_proc.symbol)->udata.p
402160484Sobrien    = symbol_get_bfdsym (entry_sym);
402233965Sjdp
402333965Sjdp  SKIP_WHITESPACE ();
402433965Sjdp  if (*input_line_pointer++ != ',')
402533965Sjdp    {
402660484Sobrien      as_warn (_("No comma after .pdesc <entryname>"));
402733965Sjdp      demand_empty_rest_of_line ();
402833965Sjdp      return;
402933965Sjdp    }
403033965Sjdp
403133965Sjdp  SKIP_WHITESPACE ();
403233965Sjdp  name = input_line_pointer;
403333965Sjdp  name_end = get_symbol_end ();
403433965Sjdp
403577298Sobrien  if (strncmp (name, "stack", 5) == 0)
4036218822Sdim    alpha_evax_proc.pdsckind = PDSC_S_K_KIND_FP_STACK;
4037218822Sdim
403877298Sobrien  else if (strncmp (name, "reg", 3) == 0)
4039218822Sdim    alpha_evax_proc.pdsckind = PDSC_S_K_KIND_FP_REGISTER;
4040218822Sdim
404177298Sobrien  else if (strncmp (name, "null", 4) == 0)
4042218822Sdim    alpha_evax_proc.pdsckind = PDSC_S_K_KIND_NULL;
4043218822Sdim
404433965Sjdp  else
404533965Sjdp    {
404660484Sobrien      as_fatal (_("unknown procedure kind"));
404733965Sjdp      demand_empty_rest_of_line ();
404833965Sjdp      return;
404933965Sjdp    }
405033965Sjdp
405133965Sjdp  *input_line_pointer = name_end;
405233965Sjdp  demand_empty_rest_of_line ();
405333965Sjdp
405433965Sjdp#ifdef md_flush_pending_output
405533965Sjdp  md_flush_pending_output ();
405633965Sjdp#endif
405733965Sjdp
405833965Sjdp  frag_align (3, 0, 0);
405933965Sjdp  p = frag_more (16);
406033965Sjdp  fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0);
406133965Sjdp  fixp->fx_done = 1;
406233965Sjdp  seginfo->literal_pool_size += 16;
406333965Sjdp
406433965Sjdp  *p = alpha_evax_proc.pdsckind
406577298Sobrien    | ((alpha_evax_proc.framereg == 29) ? PDSC_S_M_BASE_REG_IS_FP : 0);
406677298Sobrien  *(p + 1) = PDSC_S_M_NATIVE | PDSC_S_M_NO_JACKET;
406733965Sjdp
406833965Sjdp  switch (alpha_evax_proc.pdsckind)
406933965Sjdp    {
407077298Sobrien    case PDSC_S_K_KIND_NULL:
407177298Sobrien      *(p + 2) = 0;
407277298Sobrien      *(p + 3) = 0;
407377298Sobrien      break;
407477298Sobrien    case PDSC_S_K_KIND_FP_REGISTER:
407577298Sobrien      *(p + 2) = alpha_evax_proc.fp_save;
407677298Sobrien      *(p + 3) = alpha_evax_proc.ra_save;
407777298Sobrien      break;
407877298Sobrien    case PDSC_S_K_KIND_FP_STACK:
407977298Sobrien      md_number_to_chars (p + 2, (valueT) alpha_evax_proc.rsa_offset, 2);
408077298Sobrien      break;
408177298Sobrien    default:		/* impossible */
408277298Sobrien      break;
408333965Sjdp    }
408433965Sjdp
408577298Sobrien  *(p + 4) = 0;
408677298Sobrien  *(p + 5) = alpha_evax_proc.type & 0x0f;
408733965Sjdp
408833965Sjdp  /* Signature offset.  */
408977298Sobrien  md_number_to_chars (p + 6, (valueT) 0, 2);
409033965Sjdp
409177298Sobrien  fix_new_exp (frag_now, p - frag_now->fr_literal+8, 8, &exp, 0, BFD_RELOC_64);
409233965Sjdp
409333965Sjdp  if (alpha_evax_proc.pdsckind == PDSC_S_K_KIND_NULL)
409433965Sjdp    return;
409533965Sjdp
409633965Sjdp  /* Add dummy fix to make add_to_link_pool work.  */
409733965Sjdp  p = frag_more (8);
409833965Sjdp  fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0);
409933965Sjdp  fixp->fx_done = 1;
410033965Sjdp  seginfo->literal_pool_size += 8;
410133965Sjdp
410233965Sjdp  /* pdesc+16: Size.  */
410377298Sobrien  md_number_to_chars (p, (valueT) alpha_evax_proc.framesize, 4);
410433965Sjdp
410577298Sobrien  md_number_to_chars (p + 4, (valueT) 0, 2);
410633965Sjdp
410733965Sjdp  /* Entry length.  */
410877298Sobrien  md_number_to_chars (p + 6, alpha_evax_proc.prologue, 2);
410933965Sjdp
411033965Sjdp  if (alpha_evax_proc.pdsckind == PDSC_S_K_KIND_FP_REGISTER)
411133965Sjdp    return;
411233965Sjdp
411333965Sjdp  /* Add dummy fix to make add_to_link_pool work.  */
411433965Sjdp  p = frag_more (8);
411533965Sjdp  fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0);
411633965Sjdp  fixp->fx_done = 1;
411733965Sjdp  seginfo->literal_pool_size += 8;
411833965Sjdp
411933965Sjdp  /* pdesc+24: register masks.  */
412033965Sjdp
412133965Sjdp  md_number_to_chars (p, alpha_evax_proc.imask, 4);
412277298Sobrien  md_number_to_chars (p + 4, alpha_evax_proc.fmask, 4);
412333965Sjdp}
412433965Sjdp
412533965Sjdp/* Support for crash debug on vms.  */
412633965Sjdp
412733965Sjdpstatic void
4128218822Sdims_alpha_name (int ignore ATTRIBUTE_UNUSED)
412933965Sjdp{
4130218822Sdim  char *p;
413133965Sjdp  expressionS exp;
413233965Sjdp  segment_info_type *seginfo = seg_info (alpha_link_section);
413333965Sjdp
413433965Sjdp  if (now_seg != alpha_link_section)
413533965Sjdp    {
413660484Sobrien      as_bad (_(".name directive not in link (.link) section"));
413733965Sjdp      demand_empty_rest_of_line ();
413833965Sjdp      return;
413933965Sjdp    }
414033965Sjdp
414133965Sjdp  expression (&exp);
414233965Sjdp  if (exp.X_op != O_symbol)
414333965Sjdp    {
414460484Sobrien      as_warn (_(".name directive has no symbol"));
414533965Sjdp      demand_empty_rest_of_line ();
414633965Sjdp      return;
414733965Sjdp    }
414833965Sjdp
414933965Sjdp  demand_empty_rest_of_line ();
415033965Sjdp
415133965Sjdp#ifdef md_flush_pending_output
415233965Sjdp  md_flush_pending_output ();
415333965Sjdp#endif
415433965Sjdp
415533965Sjdp  frag_align (3, 0, 0);
415633965Sjdp  p = frag_more (8);
415733965Sjdp  seginfo->literal_pool_size += 8;
415833965Sjdp
415977298Sobrien  fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &exp, 0, BFD_RELOC_64);
416033965Sjdp}
416133965Sjdp
416233965Sjdpstatic void
4163218822Sdims_alpha_linkage (int ignore ATTRIBUTE_UNUSED)
416433965Sjdp{
416533965Sjdp  expressionS exp;
416633965Sjdp  char *p;
416733965Sjdp
416833965Sjdp#ifdef md_flush_pending_output
416933965Sjdp  md_flush_pending_output ();
417033965Sjdp#endif
417133965Sjdp
417233965Sjdp  expression (&exp);
417333965Sjdp  if (exp.X_op != O_symbol)
417433965Sjdp    {
417560484Sobrien      as_fatal (_("No symbol after .linkage"));
417633965Sjdp    }
417733965Sjdp  else
417833965Sjdp    {
417933965Sjdp      p = frag_more (LKP_S_K_SIZE);
418033965Sjdp      memset (p, 0, LKP_S_K_SIZE);
418133965Sjdp      fix_new_exp (frag_now, p - frag_now->fr_literal, LKP_S_K_SIZE, &exp, 0,\
418233965Sjdp		   BFD_RELOC_ALPHA_LINKAGE);
418333965Sjdp    }
418433965Sjdp  demand_empty_rest_of_line ();
418533965Sjdp}
418633965Sjdp
418733965Sjdpstatic void
4188218822Sdims_alpha_code_address (int ignore ATTRIBUTE_UNUSED)
418933965Sjdp{
419033965Sjdp  expressionS exp;
419133965Sjdp  char *p;
419233965Sjdp
419333965Sjdp#ifdef md_flush_pending_output
419433965Sjdp  md_flush_pending_output ();
419533965Sjdp#endif
419633965Sjdp
419733965Sjdp  expression (&exp);
419833965Sjdp  if (exp.X_op != O_symbol)
4199218822Sdim    as_fatal (_("No symbol after .code_address"));
420033965Sjdp  else
420133965Sjdp    {
420233965Sjdp      p = frag_more (8);
420333965Sjdp      memset (p, 0, 8);
420433965Sjdp      fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &exp, 0,\
420533965Sjdp		   BFD_RELOC_ALPHA_CODEADDR);
420633965Sjdp    }
420733965Sjdp  demand_empty_rest_of_line ();
420833965Sjdp}
420933965Sjdp
421033965Sjdpstatic void
4211218822Sdims_alpha_fp_save (int ignore ATTRIBUTE_UNUSED)
421233965Sjdp{
421333965Sjdp
421433965Sjdp  alpha_evax_proc.fp_save = tc_get_register (1);
421533965Sjdp
421633965Sjdp  demand_empty_rest_of_line ();
421733965Sjdp}
421833965Sjdp
421933965Sjdpstatic void
4220218822Sdims_alpha_mask (int ignore ATTRIBUTE_UNUSED)
422133965Sjdp{
422233965Sjdp  long val;
422333965Sjdp
422433965Sjdp  if (get_absolute_expression_and_terminator (&val) != ',')
422533965Sjdp    {
422660484Sobrien      as_warn (_("Bad .mask directive"));
422733965Sjdp      --input_line_pointer;
422833965Sjdp    }
422933965Sjdp  else
423033965Sjdp    {
423133965Sjdp      alpha_evax_proc.imask = val;
423277298Sobrien      (void) get_absolute_expression ();
423333965Sjdp    }
423433965Sjdp  demand_empty_rest_of_line ();
423533965Sjdp}
423633965Sjdp
423733965Sjdpstatic void
4238218822Sdims_alpha_fmask (int ignore ATTRIBUTE_UNUSED)
423933965Sjdp{
424033965Sjdp  long val;
424133965Sjdp
424233965Sjdp  if (get_absolute_expression_and_terminator (&val) != ',')
424333965Sjdp    {
424460484Sobrien      as_warn (_("Bad .fmask directive"));
424533965Sjdp      --input_line_pointer;
424633965Sjdp    }
424733965Sjdp  else
424833965Sjdp    {
424933965Sjdp      alpha_evax_proc.fmask = val;
425033965Sjdp      (void) get_absolute_expression ();
425133965Sjdp    }
425233965Sjdp  demand_empty_rest_of_line ();
425333965Sjdp}
425433965Sjdp
425533965Sjdpstatic void
4256218822Sdims_alpha_end (int ignore ATTRIBUTE_UNUSED)
425733965Sjdp{
425833965Sjdp  char c;
425933965Sjdp
426033965Sjdp  c = get_symbol_end ();
426133965Sjdp  *input_line_pointer = c;
426233965Sjdp  demand_empty_rest_of_line ();
426333965Sjdp  alpha_evax_proc.symbol = 0;
426433965Sjdp}
426533965Sjdp
426633965Sjdpstatic void
4267218822Sdims_alpha_file (int ignore ATTRIBUTE_UNUSED)
426833965Sjdp{
426933965Sjdp  symbolS *s;
427033965Sjdp  int length;
427133965Sjdp  static char case_hack[32];
427233965Sjdp
427333965Sjdp  sprintf (case_hack, "<CASE:%01d%01d>",
427460484Sobrien	   alpha_flag_hash_long_names, alpha_flag_show_after_trunc);
427533965Sjdp
427633965Sjdp  s = symbol_find_or_make (case_hack);
427760484Sobrien  symbol_get_bfdsym (s)->flags |= BSF_FILE;
427833965Sjdp
427933965Sjdp  get_absolute_expression ();
428033965Sjdp  s = symbol_find_or_make (demand_copy_string (&length));
428160484Sobrien  symbol_get_bfdsym (s)->flags |= BSF_FILE;
428233965Sjdp  demand_empty_rest_of_line ();
428333965Sjdp}
428433965Sjdp#endif /* OBJ_EVAX  */
428533965Sjdp
428633965Sjdp/* Handle the .gprel32 pseudo op.  */
428733965Sjdp
428833965Sjdpstatic void
4289218822Sdims_alpha_gprel32 (int ignore ATTRIBUTE_UNUSED)
429033965Sjdp{
429133965Sjdp  expressionS e;
429233965Sjdp  char *p;
429333965Sjdp
429433965Sjdp  SKIP_WHITESPACE ();
429533965Sjdp  expression (&e);
429633965Sjdp
429733965Sjdp#ifdef OBJ_ELF
429833965Sjdp  switch (e.X_op)
429933965Sjdp    {
430033965Sjdp    case O_constant:
430177298Sobrien      e.X_add_symbol = section_symbol (absolute_section);
430233965Sjdp      e.X_op = O_symbol;
430333965Sjdp      /* FALLTHRU */
430433965Sjdp    case O_symbol:
430533965Sjdp      break;
430633965Sjdp    default:
430777298Sobrien      abort ();
430833965Sjdp    }
430933965Sjdp#else
431033965Sjdp#ifdef OBJ_ECOFF
431133965Sjdp  switch (e.X_op)
431233965Sjdp    {
431333965Sjdp    case O_constant:
431433965Sjdp      e.X_add_symbol = section_symbol (absolute_section);
431533965Sjdp      /* fall through */
431633965Sjdp    case O_symbol:
431733965Sjdp      e.X_op = O_subtract;
431833965Sjdp      e.X_op_symbol = alpha_gp_symbol;
431933965Sjdp      break;
432033965Sjdp    default:
432133965Sjdp      abort ();
432233965Sjdp    }
432333965Sjdp#endif
432433965Sjdp#endif
432533965Sjdp
432633965Sjdp  if (alpha_auto_align_on && alpha_current_align < 2)
432738889Sjdp    alpha_align (2, (char *) NULL, alpha_insn_label, 0);
432833965Sjdp  if (alpha_current_align > 2)
432933965Sjdp    alpha_current_align = 2;
433033965Sjdp  alpha_insn_label = NULL;
433133965Sjdp
433233965Sjdp  p = frag_more (4);
433333965Sjdp  memset (p, 0, 4);
433477298Sobrien  fix_new_exp (frag_now, p - frag_now->fr_literal, 4,
433533965Sjdp	       &e, 0, BFD_RELOC_GPREL32);
433633965Sjdp}
433733965Sjdp
433833965Sjdp/* Handle floating point allocation pseudo-ops.  This is like the
433933965Sjdp   generic vresion, but it makes sure the current label, if any, is
434033965Sjdp   correctly aligned.  */
434133965Sjdp
434233965Sjdpstatic void
4343218822Sdims_alpha_float_cons (int type)
434433965Sjdp{
434533965Sjdp  int log_size;
434633965Sjdp
434733965Sjdp  switch (type)
434833965Sjdp    {
434933965Sjdp    default:
435033965Sjdp    case 'f':
435133965Sjdp    case 'F':
435233965Sjdp      log_size = 2;
435333965Sjdp      break;
435433965Sjdp
435533965Sjdp    case 'd':
435633965Sjdp    case 'D':
435733965Sjdp    case 'G':
435833965Sjdp      log_size = 3;
435933965Sjdp      break;
436033965Sjdp
436133965Sjdp    case 'x':
436233965Sjdp    case 'X':
436333965Sjdp    case 'p':
436433965Sjdp    case 'P':
436533965Sjdp      log_size = 4;
436633965Sjdp      break;
436733965Sjdp    }
436833965Sjdp
436933965Sjdp  if (alpha_auto_align_on && alpha_current_align < log_size)
437038889Sjdp    alpha_align (log_size, (char *) NULL, alpha_insn_label, 0);
437133965Sjdp  if (alpha_current_align > log_size)
437233965Sjdp    alpha_current_align = log_size;
437333965Sjdp  alpha_insn_label = NULL;
437433965Sjdp
437533965Sjdp  float_cons (type);
437633965Sjdp}
437733965Sjdp
437833965Sjdp/* Handle the .proc pseudo op.  We don't really do much with it except
437933965Sjdp   parse it.  */
438033965Sjdp
438133965Sjdpstatic void
4382218822Sdims_alpha_proc (int is_static ATTRIBUTE_UNUSED)
438333965Sjdp{
438433965Sjdp  char *name;
438533965Sjdp  char c;
438633965Sjdp  char *p;
438733965Sjdp  symbolS *symbolP;
438833965Sjdp  int temp;
438933965Sjdp
4390218822Sdim  /* Takes ".proc name,nargs".  */
439138889Sjdp  SKIP_WHITESPACE ();
439233965Sjdp  name = input_line_pointer;
439333965Sjdp  c = get_symbol_end ();
439433965Sjdp  p = input_line_pointer;
439533965Sjdp  symbolP = symbol_find_or_make (name);
439633965Sjdp  *p = c;
439733965Sjdp  SKIP_WHITESPACE ();
439833965Sjdp  if (*input_line_pointer != ',')
439933965Sjdp    {
440033965Sjdp      *p = 0;
440160484Sobrien      as_warn (_("Expected comma after name \"%s\""), name);
440233965Sjdp      *p = c;
440333965Sjdp      temp = 0;
440433965Sjdp      ignore_rest_of_line ();
440533965Sjdp    }
440633965Sjdp  else
440733965Sjdp    {
440833965Sjdp      input_line_pointer++;
440933965Sjdp      temp = get_absolute_expression ();
441033965Sjdp    }
441160484Sobrien  /*  *symbol_get_obj (symbolP) = (signed char) temp; */
441260484Sobrien  as_warn (_("unhandled: .proc %s,%d"), name, temp);
441333965Sjdp  demand_empty_rest_of_line ();
441433965Sjdp}
441533965Sjdp
441633965Sjdp/* Handle the .set pseudo op.  This is used to turn on and off most of
441733965Sjdp   the assembler features.  */
441833965Sjdp
441933965Sjdpstatic void
4420218822Sdims_alpha_set (int x ATTRIBUTE_UNUSED)
442133965Sjdp{
442238889Sjdp  char *name, ch, *s;
442333965Sjdp  int yesno = 1;
442433965Sjdp
442538889Sjdp  SKIP_WHITESPACE ();
442638889Sjdp  name = input_line_pointer;
442738889Sjdp  ch = get_symbol_end ();
442833965Sjdp
442933965Sjdp  s = name;
443033965Sjdp  if (s[0] == 'n' && s[1] == 'o')
443133965Sjdp    {
443233965Sjdp      yesno = 0;
443333965Sjdp      s += 2;
443433965Sjdp    }
443533965Sjdp  if (!strcmp ("reorder", s))
443633965Sjdp    /* ignore */ ;
443733965Sjdp  else if (!strcmp ("at", s))
443833965Sjdp    alpha_noat_on = !yesno;
443933965Sjdp  else if (!strcmp ("macro", s))
444033965Sjdp    alpha_macros_on = yesno;
444133965Sjdp  else if (!strcmp ("move", s))
444233965Sjdp    /* ignore */ ;
444333965Sjdp  else if (!strcmp ("volatile", s))
444433965Sjdp    /* ignore */ ;
444533965Sjdp  else
444660484Sobrien    as_warn (_("Tried to .set unrecognized mode `%s'"), name);
444733965Sjdp
444833965Sjdp  *input_line_pointer = ch;
444933965Sjdp  demand_empty_rest_of_line ();
445033965Sjdp}
445133965Sjdp
445233965Sjdp/* Handle the .base pseudo op.  This changes the assembler's notion of
445333965Sjdp   the $gp register.  */
445433965Sjdp
445533965Sjdpstatic void
4456218822Sdims_alpha_base (int ignore ATTRIBUTE_UNUSED)
445733965Sjdp{
4458218822Sdim  SKIP_WHITESPACE ();
445933965Sjdp
446033965Sjdp  if (*input_line_pointer == '$')
4461218822Sdim    {
4462218822Sdim      /* $rNN form.  */
446333965Sjdp      input_line_pointer++;
446433965Sjdp      if (*input_line_pointer == 'r')
446533965Sjdp	input_line_pointer++;
446633965Sjdp    }
446733965Sjdp
446833965Sjdp  alpha_gp_register = get_absolute_expression ();
446933965Sjdp  if (alpha_gp_register < 0 || alpha_gp_register > 31)
447033965Sjdp    {
447133965Sjdp      alpha_gp_register = AXP_REG_GP;
447260484Sobrien      as_warn (_("Bad base register, using $%d."), alpha_gp_register);
447333965Sjdp    }
447433965Sjdp
447533965Sjdp  demand_empty_rest_of_line ();
447633965Sjdp}
447733965Sjdp
447833965Sjdp/* Handle the .align pseudo-op.  This aligns to a power of two.  It
447933965Sjdp   also adjusts any current instruction label.  We treat this the same
448033965Sjdp   way the MIPS port does: .align 0 turns off auto alignment.  */
448133965Sjdp
448233965Sjdpstatic void
4483218822Sdims_alpha_align (int ignore ATTRIBUTE_UNUSED)
448433965Sjdp{
448533965Sjdp  int align;
448633965Sjdp  char fill, *pfill;
448733965Sjdp  long max_alignment = 15;
448833965Sjdp
448933965Sjdp  align = get_absolute_expression ();
449033965Sjdp  if (align > max_alignment)
449133965Sjdp    {
449233965Sjdp      align = max_alignment;
449360484Sobrien      as_bad (_("Alignment too large: %d. assumed"), align);
449433965Sjdp    }
449533965Sjdp  else if (align < 0)
449633965Sjdp    {
449760484Sobrien      as_warn (_("Alignment negative: 0 assumed"));
449833965Sjdp      align = 0;
449933965Sjdp    }
450033965Sjdp
450133965Sjdp  if (*input_line_pointer == ',')
450233965Sjdp    {
450333965Sjdp      input_line_pointer++;
450433965Sjdp      fill = get_absolute_expression ();
450533965Sjdp      pfill = &fill;
450633965Sjdp    }
450733965Sjdp  else
450833965Sjdp    pfill = NULL;
450933965Sjdp
451033965Sjdp  if (align != 0)
451133965Sjdp    {
451233965Sjdp      alpha_auto_align_on = 1;
451338889Sjdp      alpha_align (align, pfill, alpha_insn_label, 1);
451433965Sjdp    }
451533965Sjdp  else
451633965Sjdp    {
451733965Sjdp      alpha_auto_align_on = 0;
451833965Sjdp    }
451933965Sjdp
452033965Sjdp  demand_empty_rest_of_line ();
452133965Sjdp}
452233965Sjdp
452333965Sjdp/* Hook the normal string processor to reset known alignment.  */
452433965Sjdp
452533965Sjdpstatic void
4526218822Sdims_alpha_stringer (int terminate)
452733965Sjdp{
452833965Sjdp  alpha_current_align = 0;
452933965Sjdp  alpha_insn_label = NULL;
453033965Sjdp  stringer (terminate);
453133965Sjdp}
453233965Sjdp
453333965Sjdp/* Hook the normal space processing to reset known alignment.  */
453433965Sjdp
453533965Sjdpstatic void
4536218822Sdims_alpha_space (int ignore)
453733965Sjdp{
453833965Sjdp  alpha_current_align = 0;
453933965Sjdp  alpha_insn_label = NULL;
454033965Sjdp  s_space (ignore);
454133965Sjdp}
454233965Sjdp
454333965Sjdp/* Hook into cons for auto-alignment.  */
454433965Sjdp
454533965Sjdpvoid
4546218822Sdimalpha_cons_align (int size)
454733965Sjdp{
454833965Sjdp  int log_size;
454933965Sjdp
455033965Sjdp  log_size = 0;
455133965Sjdp  while ((size >>= 1) != 0)
455233965Sjdp    ++log_size;
455333965Sjdp
455433965Sjdp  if (alpha_auto_align_on && alpha_current_align < log_size)
455538889Sjdp    alpha_align (log_size, (char *) NULL, alpha_insn_label, 0);
455633965Sjdp  if (alpha_current_align > log_size)
455733965Sjdp    alpha_current_align = log_size;
455833965Sjdp  alpha_insn_label = NULL;
455933965Sjdp}
456038889Sjdp
456138889Sjdp/* Here come the .uword, .ulong, and .uquad explicitly unaligned
456238889Sjdp   pseudos.  We just turn off auto-alignment and call down to cons.  */
456338889Sjdp
456438889Sjdpstatic void
4565218822Sdims_alpha_ucons (int bytes)
456638889Sjdp{
456738889Sjdp  int hold = alpha_auto_align_on;
456838889Sjdp  alpha_auto_align_on = 0;
456938889Sjdp  cons (bytes);
457038889Sjdp  alpha_auto_align_on = hold;
457138889Sjdp}
457238889Sjdp
457338889Sjdp/* Switch the working cpu type.  */
457438889Sjdp
457538889Sjdpstatic void
4576218822Sdims_alpha_arch (int ignored ATTRIBUTE_UNUSED)
457738889Sjdp{
457838889Sjdp  char *name, ch;
457938889Sjdp  const struct cpu_type *p;
458038889Sjdp
458138889Sjdp  SKIP_WHITESPACE ();
458238889Sjdp  name = input_line_pointer;
458338889Sjdp  ch = get_symbol_end ();
458438889Sjdp
458538889Sjdp  for (p = cpu_types; p->name; ++p)
458677298Sobrien    if (strcmp (name, p->name) == 0)
458738889Sjdp      {
458877298Sobrien	alpha_target_name = p->name, alpha_target = p->flags;
458938889Sjdp	goto found;
459038889Sjdp      }
459177298Sobrien  as_warn ("Unknown CPU identifier `%s'", name);
459238889Sjdp
459338889Sjdpfound:
459438889Sjdp  *input_line_pointer = ch;
459538889Sjdp  demand_empty_rest_of_line ();
459638889Sjdp}
459733965Sjdp
459833965Sjdp#ifdef DEBUG1
459933965Sjdp/* print token expression with alpha specific extension.  */
460033965Sjdp
460133965Sjdpstatic void
4602218822Sdimalpha_print_token (FILE *f, const expressionS *exp)
460333965Sjdp{
460433965Sjdp  switch (exp->X_op)
460533965Sjdp    {
460677298Sobrien    case O_cpregister:
460777298Sobrien      putc (',', f);
460877298Sobrien      /* FALLTHRU */
460977298Sobrien    case O_pregister:
461077298Sobrien      putc ('(', f);
461177298Sobrien      {
461277298Sobrien	expressionS nexp = *exp;
461377298Sobrien	nexp.X_op = O_register;
461477298Sobrien	print_expr (f, &nexp);
461577298Sobrien      }
461677298Sobrien      putc (')', f);
461777298Sobrien      break;
461877298Sobrien    default:
461977298Sobrien      print_expr (f, exp);
462077298Sobrien      break;
462133965Sjdp    }
462233965Sjdp}
462333965Sjdp#endif
462433965Sjdp
462533965Sjdp/* The target specific pseudo-ops which we support.  */
462633965Sjdp
4627218822Sdimconst pseudo_typeS md_pseudo_table[] =
4628218822Sdim{
462933965Sjdp#ifdef OBJ_ECOFF
4630218822Sdim  {"comm", s_alpha_comm, 0},	/* OSF1 compiler does this.  */
463133965Sjdp  {"rdata", s_alpha_rdata, 0},
463233965Sjdp#endif
463333965Sjdp  {"text", s_alpha_text, 0},
463433965Sjdp  {"data", s_alpha_data, 0},
463533965Sjdp#ifdef OBJ_ECOFF
463633965Sjdp  {"sdata", s_alpha_sdata, 0},
463733965Sjdp#endif
463833965Sjdp#ifdef OBJ_ELF
463933965Sjdp  {"section", s_alpha_section, 0},
464033965Sjdp  {"section.s", s_alpha_section, 0},
464133965Sjdp  {"sect", s_alpha_section, 0},
464233965Sjdp  {"sect.s", s_alpha_section, 0},
464333965Sjdp#endif
464433965Sjdp#ifdef OBJ_EVAX
464533965Sjdp  { "pdesc", s_alpha_pdesc, 0},
464633965Sjdp  { "name", s_alpha_name, 0},
464733965Sjdp  { "linkage", s_alpha_linkage, 0},
464833965Sjdp  { "code_address", s_alpha_code_address, 0},
464933965Sjdp  { "ent", s_alpha_ent, 0},
465033965Sjdp  { "frame", s_alpha_frame, 0},
465133965Sjdp  { "fp_save", s_alpha_fp_save, 0},
465233965Sjdp  { "mask", s_alpha_mask, 0},
465333965Sjdp  { "fmask", s_alpha_fmask, 0},
465433965Sjdp  { "end", s_alpha_end, 0},
465533965Sjdp  { "file", s_alpha_file, 0},
465633965Sjdp  { "rdata", s_alpha_section, 1},
465738889Sjdp  { "comm", s_alpha_comm, 0},
465833965Sjdp  { "link", s_alpha_section, 3},
465933965Sjdp  { "ctors", s_alpha_section, 4},
466033965Sjdp  { "dtors", s_alpha_section, 5},
466133965Sjdp#endif
466260484Sobrien#ifdef OBJ_ELF
466360484Sobrien  /* Frame related pseudos.  */
466460484Sobrien  {"ent", s_alpha_ent, 0},
466560484Sobrien  {"end", s_alpha_end, 0},
466660484Sobrien  {"mask", s_alpha_mask, 0},
466760484Sobrien  {"fmask", s_alpha_mask, 1},
466860484Sobrien  {"frame", s_alpha_frame, 0},
466960484Sobrien  {"prologue", s_alpha_prologue, 0},
4670130561Sobrien  {"file", s_alpha_file, 5},
467177298Sobrien  {"loc", s_alpha_loc, 9},
467277298Sobrien  {"stabs", s_alpha_stab, 's'},
467377298Sobrien  {"stabn", s_alpha_stab, 'n'},
4674130561Sobrien  {"usepv", s_alpha_usepv, 0},
467560484Sobrien  /* COFF debugging related pseudos.  */
467660484Sobrien  {"begin", s_alpha_coff_wrapper, 0},
467760484Sobrien  {"bend", s_alpha_coff_wrapper, 1},
467860484Sobrien  {"def", s_alpha_coff_wrapper, 2},
467960484Sobrien  {"dim", s_alpha_coff_wrapper, 3},
468060484Sobrien  {"endef", s_alpha_coff_wrapper, 4},
468177298Sobrien  {"scl", s_alpha_coff_wrapper, 5},
468277298Sobrien  {"tag", s_alpha_coff_wrapper, 6},
468377298Sobrien  {"val", s_alpha_coff_wrapper, 7},
468460484Sobrien#else
468560484Sobrien  {"prologue", s_ignore, 0},
468660484Sobrien#endif
468733965Sjdp  {"gprel32", s_alpha_gprel32, 0},
468833965Sjdp  {"t_floating", s_alpha_float_cons, 'd'},
468933965Sjdp  {"s_floating", s_alpha_float_cons, 'f'},
469033965Sjdp  {"f_floating", s_alpha_float_cons, 'F'},
469133965Sjdp  {"g_floating", s_alpha_float_cons, 'G'},
469233965Sjdp  {"d_floating", s_alpha_float_cons, 'D'},
469333965Sjdp
469433965Sjdp  {"proc", s_alpha_proc, 0},
469533965Sjdp  {"aproc", s_alpha_proc, 1},
469633965Sjdp  {"set", s_alpha_set, 0},
469733965Sjdp  {"reguse", s_ignore, 0},
469833965Sjdp  {"livereg", s_ignore, 0},
469933965Sjdp  {"base", s_alpha_base, 0},		/*??*/
470033965Sjdp  {"option", s_ignore, 0},
470133965Sjdp  {"aent", s_ignore, 0},
470233965Sjdp  {"ugen", s_ignore, 0},
470333965Sjdp  {"eflag", s_ignore, 0},
470433965Sjdp
470533965Sjdp  {"align", s_alpha_align, 0},
470633965Sjdp  {"double", s_alpha_float_cons, 'd'},
470733965Sjdp  {"float", s_alpha_float_cons, 'f'},
470833965Sjdp  {"single", s_alpha_float_cons, 'f'},
470933965Sjdp  {"ascii", s_alpha_stringer, 0},
471033965Sjdp  {"asciz", s_alpha_stringer, 1},
471133965Sjdp  {"string", s_alpha_stringer, 1},
471233965Sjdp  {"space", s_alpha_space, 0},
471333965Sjdp  {"skip", s_alpha_space, 0},
471433965Sjdp  {"zero", s_alpha_space, 0},
471533965Sjdp
471638889Sjdp/* Unaligned data pseudos.  */
471738889Sjdp  {"uword", s_alpha_ucons, 2},
471838889Sjdp  {"ulong", s_alpha_ucons, 4},
471938889Sjdp  {"uquad", s_alpha_ucons, 8},
472038889Sjdp
472138889Sjdp#ifdef OBJ_ELF
472238889Sjdp/* Dwarf wants these versions of unaligned.  */
472338889Sjdp  {"2byte", s_alpha_ucons, 2},
472438889Sjdp  {"4byte", s_alpha_ucons, 4},
472538889Sjdp  {"8byte", s_alpha_ucons, 8},
472638889Sjdp#endif
472738889Sjdp
472833965Sjdp/* We don't do any optimizing, so we can safely ignore these.  */
472933965Sjdp  {"noalias", s_ignore, 0},
473033965Sjdp  {"alias", s_ignore, 0},
473133965Sjdp
473238889Sjdp  {"arch", s_alpha_arch, 0},
473338889Sjdp
473433965Sjdp  {NULL, 0, 0},
473533965Sjdp};
473633965Sjdp
473733965Sjdp#ifdef OBJ_ECOFF
473833965Sjdp
473933965Sjdp/* @@@ GP selection voodoo.  All of this seems overly complicated and
474033965Sjdp   unnecessary; which is the primary reason it's for ECOFF only.  */
4741130561Sobrienstatic inline void maybe_set_gp PARAMS ((asection *));
474233965Sjdp
474333965Sjdpstatic inline void
4744218822Sdimmaybe_set_gp (asection *sec)
474533965Sjdp{
474633965Sjdp  bfd_vma vma;
4747218822Sdim
474833965Sjdp  if (!sec)
474933965Sjdp    return;
475033965Sjdp  vma = bfd_get_section_vma (foo, sec);
475133965Sjdp  if (vma && vma < alpha_gp_value)
475233965Sjdp    alpha_gp_value = vma;
475333965Sjdp}
475433965Sjdp
475533965Sjdpstatic void
4756218822Sdimselect_gp_value (void)
475733965Sjdp{
475833965Sjdp  assert (alpha_gp_value == 0);
475933965Sjdp
476033965Sjdp  /* Get minus-one in whatever width...  */
476177298Sobrien  alpha_gp_value = 0;
476277298Sobrien  alpha_gp_value--;
476333965Sjdp
476433965Sjdp  /* Select the smallest VMA of these existing sections.  */
476533965Sjdp  maybe_set_gp (alpha_lita_section);
476633965Sjdp
476733965Sjdp/* @@ Will a simple 0x8000 work here?  If not, why not?  */
476833965Sjdp#define GP_ADJUSTMENT	(0x8000 - 0x10)
476933965Sjdp
477033965Sjdp  alpha_gp_value += GP_ADJUSTMENT;
477133965Sjdp
477233965Sjdp  S_SET_VALUE (alpha_gp_symbol, alpha_gp_value);
477333965Sjdp
477433965Sjdp#ifdef DEBUG1
477560484Sobrien  printf (_("Chose GP value of %lx\n"), alpha_gp_value);
477633965Sjdp#endif
477733965Sjdp}
477833965Sjdp#endif /* OBJ_ECOFF */
477933965Sjdp
478089857Sobrien#ifdef OBJ_ELF
478189857Sobrien/* Map 's' to SHF_ALPHA_GPREL.  */
478289857Sobrien
478389857Sobrienint
4784218822Sdimalpha_elf_section_letter (int letter, char **ptr_msg)
478589857Sobrien{
478689857Sobrien  if (letter == 's')
478789857Sobrien    return SHF_ALPHA_GPREL;
478889857Sobrien
4789104834Sobrien  *ptr_msg = _("Bad .section directive: want a,s,w,x,M,S,G,T in string");
4790130561Sobrien  return -1;
479189857Sobrien}
479289857Sobrien
479389857Sobrien/* Map SHF_ALPHA_GPREL to SEC_SMALL_DATA.  */
479489857Sobrien
479589857Sobrienflagword
4796218822Sdimalpha_elf_section_flags (flagword flags, int attr, int type ATTRIBUTE_UNUSED)
479789857Sobrien{
479889857Sobrien  if (attr & SHF_ALPHA_GPREL)
479989857Sobrien    flags |= SEC_SMALL_DATA;
480089857Sobrien  return flags;
480189857Sobrien}
480289857Sobrien#endif /* OBJ_ELF */
480389857Sobrien
480477298Sobrien/* This is called from HANDLE_ALIGN in write.c.  Fill in the contents
480577298Sobrien   of an rs_align_code fragment.  */
480677298Sobrien
480777298Sobrienvoid
4808218822Sdimalpha_handle_align (fragS *fragp)
480977298Sobrien{
481089857Sobrien  static char const unop[4] = { 0x00, 0x00, 0xfe, 0x2f };
4811218822Sdim  static char const nopunop[8] =
4812218822Sdim  {
481377298Sobrien    0x1f, 0x04, 0xff, 0x47,
481489857Sobrien    0x00, 0x00, 0xfe, 0x2f
481577298Sobrien  };
481677298Sobrien
481777298Sobrien  int bytes, fix;
481877298Sobrien  char *p;
481977298Sobrien
482077298Sobrien  if (fragp->fr_type != rs_align_code)
482177298Sobrien    return;
482277298Sobrien
482377298Sobrien  bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
482477298Sobrien  p = fragp->fr_literal + fragp->fr_fix;
482577298Sobrien  fix = 0;
482677298Sobrien
482777298Sobrien  if (bytes & 3)
482877298Sobrien    {
482977298Sobrien      fix = bytes & 3;
483077298Sobrien      memset (p, 0, fix);
483177298Sobrien      p += fix;
483277298Sobrien      bytes -= fix;
483377298Sobrien    }
483477298Sobrien
483577298Sobrien  if (bytes & 4)
483677298Sobrien    {
483777298Sobrien      memcpy (p, unop, 4);
483877298Sobrien      p += 4;
483977298Sobrien      bytes -= 4;
484077298Sobrien      fix += 4;
484177298Sobrien    }
484277298Sobrien
484377298Sobrien  memcpy (p, nopunop, 8);
484477298Sobrien
484577298Sobrien  fragp->fr_fix += fix;
484677298Sobrien  fragp->fr_var = 8;
484777298Sobrien}
4848218822Sdim
4849218822Sdim/* Public interface functions.  */
485077298Sobrien
4851218822Sdim/* This function is called once, at assembler startup time.  It sets
4852218822Sdim   up all the tables, etc. that the MD part of the assembler will
4853218822Sdim   need, that can be determined before arguments are parsed.  */
4854218822Sdim
4855218822Sdimvoid
4856218822Sdimmd_begin (void)
4857218822Sdim{
4858218822Sdim  unsigned int i;
4859218822Sdim
4860218822Sdim  /* Verify that X_op field is wide enough.  */
4861218822Sdim  {
4862218822Sdim    expressionS e;
4863218822Sdim
4864218822Sdim    e.X_op = O_max;
4865218822Sdim    assert (e.X_op == O_max);
4866218822Sdim  }
4867218822Sdim
4868218822Sdim  /* Create the opcode hash table.  */
4869218822Sdim  alpha_opcode_hash = hash_new ();
4870218822Sdim
4871218822Sdim  for (i = 0; i < alpha_num_opcodes;)
4872218822Sdim    {
4873218822Sdim      const char *name, *retval, *slash;
4874218822Sdim
4875218822Sdim      name = alpha_opcodes[i].name;
4876218822Sdim      retval = hash_insert (alpha_opcode_hash, name, (void *) &alpha_opcodes[i]);
4877218822Sdim      if (retval)
4878218822Sdim	as_fatal (_("internal error: can't hash opcode `%s': %s"),
4879218822Sdim		  name, retval);
4880218822Sdim
4881218822Sdim      /* Some opcodes include modifiers of various sorts with a "/mod"
4882218822Sdim	 syntax, like the architecture manual suggests.  However, for
4883218822Sdim	 use with gcc at least, we also need access to those same opcodes
4884218822Sdim	 without the "/".  */
4885218822Sdim
4886218822Sdim      if ((slash = strchr (name, '/')) != NULL)
4887218822Sdim	{
4888218822Sdim	  char *p = xmalloc (strlen (name));
4889218822Sdim
4890218822Sdim	  memcpy (p, name, slash - name);
4891218822Sdim	  strcpy (p + (slash - name), slash + 1);
4892218822Sdim
4893218822Sdim	  (void) hash_insert (alpha_opcode_hash, p, (void *) &alpha_opcodes[i]);
4894218822Sdim	  /* Ignore failures -- the opcode table does duplicate some
4895218822Sdim	     variants in different forms, like "hw_stq" and "hw_st/q".  */
4896218822Sdim	}
4897218822Sdim
4898218822Sdim      while (++i < alpha_num_opcodes
4899218822Sdim	     && (alpha_opcodes[i].name == name
4900218822Sdim		 || !strcmp (alpha_opcodes[i].name, name)))
4901218822Sdim	continue;
4902218822Sdim    }
4903218822Sdim
4904218822Sdim  /* Create the macro hash table.  */
4905218822Sdim  alpha_macro_hash = hash_new ();
4906218822Sdim
4907218822Sdim  for (i = 0; i < alpha_num_macros;)
4908218822Sdim    {
4909218822Sdim      const char *name, *retval;
4910218822Sdim
4911218822Sdim      name = alpha_macros[i].name;
4912218822Sdim      retval = hash_insert (alpha_macro_hash, name, (void *) &alpha_macros[i]);
4913218822Sdim      if (retval)
4914218822Sdim	as_fatal (_("internal error: can't hash macro `%s': %s"),
4915218822Sdim		  name, retval);
4916218822Sdim
4917218822Sdim      while (++i < alpha_num_macros
4918218822Sdim	     && (alpha_macros[i].name == name
4919218822Sdim		 || !strcmp (alpha_macros[i].name, name)))
4920218822Sdim	continue;
4921218822Sdim    }
4922218822Sdim
4923218822Sdim  /* Construct symbols for each of the registers.  */
4924218822Sdim  for (i = 0; i < 32; ++i)
4925218822Sdim    {
4926218822Sdim      char name[4];
4927218822Sdim
4928218822Sdim      sprintf (name, "$%d", i);
4929218822Sdim      alpha_register_table[i] = symbol_create (name, reg_section, i,
4930218822Sdim					       &zero_address_frag);
4931218822Sdim    }
4932218822Sdim
4933218822Sdim  for (; i < 64; ++i)
4934218822Sdim    {
4935218822Sdim      char name[5];
4936218822Sdim
4937218822Sdim      sprintf (name, "$f%d", i - 32);
4938218822Sdim      alpha_register_table[i] = symbol_create (name, reg_section, i,
4939218822Sdim					       &zero_address_frag);
4940218822Sdim    }
4941218822Sdim
4942218822Sdim  /* Create the special symbols and sections we'll be using.  */
4943218822Sdim
4944218822Sdim  /* So .sbss will get used for tiny objects.  */
4945218822Sdim  bfd_set_gp_size (stdoutput, g_switch_value);
4946218822Sdim
4947218822Sdim#ifdef OBJ_ECOFF
4948218822Sdim  create_literal_section (".lita", &alpha_lita_section, &alpha_lita_symbol);
4949218822Sdim
4950218822Sdim  /* For handling the GP, create a symbol that won't be output in the
4951218822Sdim     symbol table.  We'll edit it out of relocs later.  */
4952218822Sdim  alpha_gp_symbol = symbol_create ("<GP value>", alpha_lita_section, 0x8000,
4953218822Sdim				   &zero_address_frag);
4954218822Sdim#endif
4955218822Sdim
4956218822Sdim#ifdef OBJ_EVAX
4957218822Sdim  create_literal_section (".link", &alpha_link_section, &alpha_link_symbol);
4958218822Sdim#endif
4959218822Sdim
4960218822Sdim#ifdef OBJ_ELF
4961218822Sdim  if (ECOFF_DEBUGGING)
4962218822Sdim    {
4963218822Sdim      segT sec = subseg_new (".mdebug", (subsegT) 0);
4964218822Sdim      bfd_set_section_flags (stdoutput, sec, SEC_HAS_CONTENTS | SEC_READONLY);
4965218822Sdim      bfd_set_section_alignment (stdoutput, sec, 3);
4966218822Sdim    }
4967218822Sdim#endif
4968218822Sdim
4969218822Sdim  /* Create literal lookup hash table.  */
4970218822Sdim  alpha_literal_hash = hash_new ();
4971218822Sdim
4972218822Sdim  subseg_set (text_section, 0);
4973218822Sdim}
4974218822Sdim
4975218822Sdim/* The public interface to the instruction assembler.  */
4976218822Sdim
4977218822Sdimvoid
4978218822Sdimmd_assemble (char *str)
4979218822Sdim{
4980218822Sdim  /* Current maximum is 13.  */
4981218822Sdim  char opname[32];
4982218822Sdim  expressionS tok[MAX_INSN_ARGS];
4983218822Sdim  int ntok, trunclen;
4984218822Sdim  size_t opnamelen;
4985218822Sdim
4986218822Sdim  /* Split off the opcode.  */
4987218822Sdim  opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_/46819");
4988218822Sdim  trunclen = (opnamelen < sizeof (opname) - 1
4989218822Sdim	      ? opnamelen
4990218822Sdim	      : sizeof (opname) - 1);
4991218822Sdim  memcpy (opname, str, trunclen);
4992218822Sdim  opname[trunclen] = '\0';
4993218822Sdim
4994218822Sdim  /* Tokenize the rest of the line.  */
4995218822Sdim  if ((ntok = tokenize_arguments (str + opnamelen, tok, MAX_INSN_ARGS)) < 0)
4996218822Sdim    {
4997218822Sdim      if (ntok != TOKENIZE_ERROR_REPORT)
4998218822Sdim	as_bad (_("syntax error"));
4999218822Sdim
5000218822Sdim      return;
5001218822Sdim    }
5002218822Sdim
5003218822Sdim  /* Finish it off.  */
5004218822Sdim  assemble_tokens (opname, tok, ntok, alpha_macros_on);
5005218822Sdim}
5006218822Sdim
5007218822Sdim/* Round up a section's size to the appropriate boundary.  */
5008218822Sdim
5009218822SdimvalueT
5010218822Sdimmd_section_align (segT seg, valueT size)
5011218822Sdim{
5012218822Sdim  int align = bfd_get_section_alignment (stdoutput, seg);
5013218822Sdim  valueT mask = ((valueT) 1 << align) - 1;
5014218822Sdim
5015218822Sdim  return (size + mask) & ~mask;
5016218822Sdim}
5017218822Sdim
5018218822Sdim/* Turn a string in input_line_pointer into a floating point constant
5019218822Sdim   of type TYPE, and store the appropriate bytes in *LITP.  The number
5020218822Sdim   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
5021218822Sdim   returned, or NULL on OK.  */
5022218822Sdim
5023218822Sdim/* Equal to MAX_PRECISION in atof-ieee.c.  */
5024218822Sdim#define MAX_LITTLENUMS 6
5025218822Sdim
5026218822Sdimextern char *vax_md_atof (int, char *, int *);
5027218822Sdim
5028218822Sdimchar *
5029218822Sdimmd_atof (int type, char *litP, int *sizeP)
5030218822Sdim{
5031218822Sdim  int prec;
5032218822Sdim  LITTLENUM_TYPE words[MAX_LITTLENUMS];
5033218822Sdim  LITTLENUM_TYPE *wordP;
5034218822Sdim  char *t;
5035218822Sdim
5036218822Sdim  switch (type)
5037218822Sdim    {
5038218822Sdim      /* VAX floats.  */
5039218822Sdim    case 'G':
5040218822Sdim      /* VAX md_atof doesn't like "G" for some reason.  */
5041218822Sdim      type = 'g';
5042218822Sdim    case 'F':
5043218822Sdim    case 'D':
5044218822Sdim      return vax_md_atof (type, litP, sizeP);
5045218822Sdim
5046218822Sdim      /* IEEE floats.  */
5047218822Sdim    case 'f':
5048218822Sdim      prec = 2;
5049218822Sdim      break;
5050218822Sdim
5051218822Sdim    case 'd':
5052218822Sdim      prec = 4;
5053218822Sdim      break;
5054218822Sdim
5055218822Sdim    case 'x':
5056218822Sdim    case 'X':
5057218822Sdim      prec = 6;
5058218822Sdim      break;
5059218822Sdim
5060218822Sdim    case 'p':
5061218822Sdim    case 'P':
5062218822Sdim      prec = 6;
5063218822Sdim      break;
5064218822Sdim
5065218822Sdim    default:
5066218822Sdim      *sizeP = 0;
5067218822Sdim      return _("Bad call to MD_ATOF()");
5068218822Sdim    }
5069218822Sdim  t = atof_ieee (input_line_pointer, type, words);
5070218822Sdim  if (t)
5071218822Sdim    input_line_pointer = t;
5072218822Sdim  *sizeP = prec * sizeof (LITTLENUM_TYPE);
5073218822Sdim
5074218822Sdim  for (wordP = words + prec - 1; prec--;)
5075218822Sdim    {
5076218822Sdim      md_number_to_chars (litP, (long) (*wordP--), sizeof (LITTLENUM_TYPE));
5077218822Sdim      litP += sizeof (LITTLENUM_TYPE);
5078218822Sdim    }
5079218822Sdim
5080218822Sdim  return 0;
5081218822Sdim}
5082218822Sdim
5083218822Sdim/* Take care of the target-specific command-line options.  */
5084218822Sdim
5085218822Sdimint
5086218822Sdimmd_parse_option (int c, char *arg)
5087218822Sdim{
5088218822Sdim  switch (c)
5089218822Sdim    {
5090218822Sdim    case 'F':
5091218822Sdim      alpha_nofloats_on = 1;
5092218822Sdim      break;
5093218822Sdim
5094218822Sdim    case OPTION_32ADDR:
5095218822Sdim      alpha_addr32_on = 1;
5096218822Sdim      break;
5097218822Sdim
5098218822Sdim    case 'g':
5099218822Sdim      alpha_debug = 1;
5100218822Sdim      break;
5101218822Sdim
5102218822Sdim    case 'G':
5103218822Sdim      g_switch_value = atoi (arg);
5104218822Sdim      break;
5105218822Sdim
5106218822Sdim    case 'm':
5107218822Sdim      {
5108218822Sdim	const struct cpu_type *p;
5109218822Sdim
5110218822Sdim	for (p = cpu_types; p->name; ++p)
5111218822Sdim	  if (strcmp (arg, p->name) == 0)
5112218822Sdim	    {
5113218822Sdim	      alpha_target_name = p->name, alpha_target = p->flags;
5114218822Sdim	      goto found;
5115218822Sdim	    }
5116218822Sdim	as_warn (_("Unknown CPU identifier `%s'"), arg);
5117218822Sdim      found:;
5118218822Sdim      }
5119218822Sdim      break;
5120218822Sdim
5121218822Sdim#ifdef OBJ_EVAX
5122218822Sdim    case '+':			/* For g++.  Hash any name > 63 chars long.  */
5123218822Sdim      alpha_flag_hash_long_names = 1;
5124218822Sdim      break;
5125218822Sdim
5126218822Sdim    case 'H':			/* Show new symbol after hash truncation.  */
5127218822Sdim      alpha_flag_show_after_trunc = 1;
5128218822Sdim      break;
5129218822Sdim
5130218822Sdim    case 'h':			/* For gnu-c/vax compatibility.  */
5131218822Sdim      break;
5132218822Sdim#endif
5133218822Sdim
5134218822Sdim    case OPTION_RELAX:
5135218822Sdim      alpha_flag_relax = 1;
5136218822Sdim      break;
5137218822Sdim
5138218822Sdim#ifdef OBJ_ELF
5139218822Sdim    case OPTION_MDEBUG:
5140218822Sdim      alpha_flag_mdebug = 1;
5141218822Sdim      break;
5142218822Sdim    case OPTION_NO_MDEBUG:
5143218822Sdim      alpha_flag_mdebug = 0;
5144218822Sdim      break;
5145218822Sdim#endif
5146218822Sdim
5147218822Sdim    default:
5148218822Sdim      return 0;
5149218822Sdim    }
5150218822Sdim
5151218822Sdim  return 1;
5152218822Sdim}
5153218822Sdim
5154218822Sdim/* Print a description of the command-line options that we accept.  */
5155218822Sdim
5156218822Sdimvoid
5157218822Sdimmd_show_usage (FILE *stream)
5158218822Sdim{
5159218822Sdim  fputs (_("\
5160218822SdimAlpha options:\n\
5161218822Sdim-32addr			treat addresses as 32-bit values\n\
5162218822Sdim-F			lack floating point instructions support\n\
5163218822Sdim-mev4 | -mev45 | -mev5 | -mev56 | -mpca56 | -mev6 | -mev67 | -mev68 | -mall\n\
5164218822Sdim			specify variant of Alpha architecture\n\
5165218822Sdim-m21064 | -m21066 | -m21164 | -m21164a | -m21164pc | -m21264 | -m21264a | -m21264b\n\
5166218822Sdim			these variants include PALcode opcodes\n"),
5167218822Sdim	stream);
5168218822Sdim#ifdef OBJ_EVAX
5169218822Sdim  fputs (_("\
5170218822SdimVMS options:\n\
5171218822Sdim-+			hash encode (don't truncate) names longer than 64 characters\n\
5172218822Sdim-H			show new symbol after hash truncation\n"),
5173218822Sdim	stream);
5174218822Sdim#endif
5175218822Sdim}
5176218822Sdim
5177218822Sdim/* Decide from what point a pc-relative relocation is relative to,
5178218822Sdim   relative to the pc-relative fixup.  Er, relatively speaking.  */
5179218822Sdim
5180218822Sdimlong
5181218822Sdimmd_pcrel_from (fixS *fixP)
5182218822Sdim{
5183218822Sdim  valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
5184218822Sdim
5185218822Sdim  switch (fixP->fx_r_type)
5186218822Sdim    {
5187218822Sdim    case BFD_RELOC_23_PCREL_S2:
5188218822Sdim    case BFD_RELOC_ALPHA_HINT:
5189218822Sdim    case BFD_RELOC_ALPHA_BRSGP:
5190218822Sdim      return addr + 4;
5191218822Sdim    default:
5192218822Sdim      return addr;
5193218822Sdim    }
5194218822Sdim}
5195218822Sdim
5196218822Sdim/* Attempt to simplify or even eliminate a fixup.  The return value is
5197218822Sdim   ignored; perhaps it was once meaningful, but now it is historical.
5198218822Sdim   To indicate that a fixup has been eliminated, set fixP->fx_done.
5199218822Sdim
5200218822Sdim   For ELF, here it is that we transform the GPDISP_HI16 reloc we used
5201218822Sdim   internally into the GPDISP reloc used externally.  We had to do
5202218822Sdim   this so that we'd have the GPDISP_LO16 reloc as a tag to compute
5203218822Sdim   the distance to the "lda" instruction for setting the addend to
5204218822Sdim   GPDISP.  */
5205218822Sdim
5206218822Sdimvoid
5207218822Sdimmd_apply_fix (fixS *fixP, valueT * valP, segT seg)
5208218822Sdim{
5209218822Sdim  char * const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
5210218822Sdim  valueT value = * valP;
5211218822Sdim  unsigned image, size;
5212218822Sdim
5213218822Sdim  switch (fixP->fx_r_type)
5214218822Sdim    {
5215218822Sdim      /* The GPDISP relocations are processed internally with a symbol
5216218822Sdim	 referring to the current function's section;  we need to drop
5217218822Sdim	 in a value which, when added to the address of the start of
5218218822Sdim	 the function, gives the desired GP.  */
5219218822Sdim    case BFD_RELOC_ALPHA_GPDISP_HI16:
5220218822Sdim      {
5221218822Sdim	fixS *next = fixP->fx_next;
5222218822Sdim
5223218822Sdim	/* With user-specified !gpdisp relocations, we can be missing
5224218822Sdim	   the matching LO16 reloc.  We will have already issued an
5225218822Sdim	   error message.  */
5226218822Sdim	if (next)
5227218822Sdim	  fixP->fx_offset = (next->fx_frag->fr_address + next->fx_where
5228218822Sdim			     - fixP->fx_frag->fr_address - fixP->fx_where);
5229218822Sdim
5230218822Sdim	value = (value - sign_extend_16 (value)) >> 16;
5231218822Sdim      }
5232218822Sdim#ifdef OBJ_ELF
5233218822Sdim      fixP->fx_r_type = BFD_RELOC_ALPHA_GPDISP;
5234218822Sdim#endif
5235218822Sdim      goto do_reloc_gp;
5236218822Sdim
5237218822Sdim    case BFD_RELOC_ALPHA_GPDISP_LO16:
5238218822Sdim      value = sign_extend_16 (value);
5239218822Sdim      fixP->fx_offset = 0;
5240218822Sdim#ifdef OBJ_ELF
5241218822Sdim      fixP->fx_done = 1;
5242218822Sdim#endif
5243218822Sdim
5244218822Sdim    do_reloc_gp:
5245218822Sdim      fixP->fx_addsy = section_symbol (seg);
5246218822Sdim      md_number_to_chars (fixpos, value, 2);
5247218822Sdim      break;
5248218822Sdim
5249218822Sdim    case BFD_RELOC_16:
5250218822Sdim      if (fixP->fx_pcrel)
5251218822Sdim	fixP->fx_r_type = BFD_RELOC_16_PCREL;
5252218822Sdim      size = 2;
5253218822Sdim      goto do_reloc_xx;
5254218822Sdim
5255218822Sdim    case BFD_RELOC_32:
5256218822Sdim      if (fixP->fx_pcrel)
5257218822Sdim	fixP->fx_r_type = BFD_RELOC_32_PCREL;
5258218822Sdim      size = 4;
5259218822Sdim      goto do_reloc_xx;
5260218822Sdim
5261218822Sdim    case BFD_RELOC_64:
5262218822Sdim      if (fixP->fx_pcrel)
5263218822Sdim	fixP->fx_r_type = BFD_RELOC_64_PCREL;
5264218822Sdim      size = 8;
5265218822Sdim
5266218822Sdim    do_reloc_xx:
5267218822Sdim      if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0)
5268218822Sdim	{
5269218822Sdim	  md_number_to_chars (fixpos, value, size);
5270218822Sdim	  goto done;
5271218822Sdim	}
5272218822Sdim      return;
5273218822Sdim
5274218822Sdim#ifdef OBJ_ECOFF
5275218822Sdim    case BFD_RELOC_GPREL32:
5276218822Sdim      assert (fixP->fx_subsy == alpha_gp_symbol);
5277218822Sdim      fixP->fx_subsy = 0;
5278218822Sdim      /* FIXME: inherited this obliviousness of `value' -- why?  */
5279218822Sdim      md_number_to_chars (fixpos, -alpha_gp_value, 4);
5280218822Sdim      break;
5281218822Sdim#else
5282218822Sdim    case BFD_RELOC_GPREL32:
5283218822Sdim#endif
5284218822Sdim    case BFD_RELOC_GPREL16:
5285218822Sdim    case BFD_RELOC_ALPHA_GPREL_HI16:
5286218822Sdim    case BFD_RELOC_ALPHA_GPREL_LO16:
5287218822Sdim      return;
5288218822Sdim
5289218822Sdim    case BFD_RELOC_23_PCREL_S2:
5290218822Sdim      if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0)
5291218822Sdim	{
5292218822Sdim	  image = bfd_getl32 (fixpos);
5293218822Sdim	  image = (image & ~0x1FFFFF) | ((value >> 2) & 0x1FFFFF);
5294218822Sdim	  goto write_done;
5295218822Sdim	}
5296218822Sdim      return;
5297218822Sdim
5298218822Sdim    case BFD_RELOC_ALPHA_HINT:
5299218822Sdim      if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0)
5300218822Sdim	{
5301218822Sdim	  image = bfd_getl32 (fixpos);
5302218822Sdim	  image = (image & ~0x3FFF) | ((value >> 2) & 0x3FFF);
5303218822Sdim	  goto write_done;
5304218822Sdim	}
5305218822Sdim      return;
5306218822Sdim
5307218822Sdim#ifdef OBJ_ELF
5308218822Sdim    case BFD_RELOC_ALPHA_BRSGP:
5309218822Sdim      return;
5310218822Sdim
5311218822Sdim    case BFD_RELOC_ALPHA_TLSGD:
5312218822Sdim    case BFD_RELOC_ALPHA_TLSLDM:
5313218822Sdim    case BFD_RELOC_ALPHA_GOTDTPREL16:
5314218822Sdim    case BFD_RELOC_ALPHA_DTPREL_HI16:
5315218822Sdim    case BFD_RELOC_ALPHA_DTPREL_LO16:
5316218822Sdim    case BFD_RELOC_ALPHA_DTPREL16:
5317218822Sdim    case BFD_RELOC_ALPHA_GOTTPREL16:
5318218822Sdim    case BFD_RELOC_ALPHA_TPREL_HI16:
5319218822Sdim    case BFD_RELOC_ALPHA_TPREL_LO16:
5320218822Sdim    case BFD_RELOC_ALPHA_TPREL16:
5321218822Sdim      if (fixP->fx_addsy)
5322218822Sdim	S_SET_THREAD_LOCAL (fixP->fx_addsy);
5323218822Sdim      return;
5324218822Sdim#endif
5325218822Sdim
5326218822Sdim#ifdef OBJ_ECOFF
5327218822Sdim    case BFD_RELOC_ALPHA_LITERAL:
5328218822Sdim      md_number_to_chars (fixpos, value, 2);
5329218822Sdim      return;
5330218822Sdim#endif
5331218822Sdim    case BFD_RELOC_ALPHA_ELF_LITERAL:
5332218822Sdim    case BFD_RELOC_ALPHA_LITUSE:
5333218822Sdim    case BFD_RELOC_ALPHA_LINKAGE:
5334218822Sdim    case BFD_RELOC_ALPHA_CODEADDR:
5335218822Sdim      return;
5336218822Sdim
5337218822Sdim    case BFD_RELOC_VTABLE_INHERIT:
5338218822Sdim    case BFD_RELOC_VTABLE_ENTRY:
5339218822Sdim      return;
5340218822Sdim
5341218822Sdim    default:
5342218822Sdim      {
5343218822Sdim	const struct alpha_operand *operand;
5344218822Sdim
5345218822Sdim	if ((int) fixP->fx_r_type >= 0)
5346218822Sdim	  as_fatal (_("unhandled relocation type %s"),
5347218822Sdim		    bfd_get_reloc_code_name (fixP->fx_r_type));
5348218822Sdim
5349218822Sdim	assert (-(int) fixP->fx_r_type < (int) alpha_num_operands);
5350218822Sdim	operand = &alpha_operands[-(int) fixP->fx_r_type];
5351218822Sdim
5352218822Sdim	/* The rest of these fixups only exist internally during symbol
5353218822Sdim	   resolution and have no representation in the object file.
5354218822Sdim	   Therefore they must be completely resolved as constants.  */
5355218822Sdim
5356218822Sdim	if (fixP->fx_addsy != 0
5357218822Sdim	    && S_GET_SEGMENT (fixP->fx_addsy) != absolute_section)
5358218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
5359218822Sdim			_("non-absolute expression in constant field"));
5360218822Sdim
5361218822Sdim	image = bfd_getl32 (fixpos);
5362218822Sdim	image = insert_operand (image, operand, (offsetT) value,
5363218822Sdim				fixP->fx_file, fixP->fx_line);
5364218822Sdim      }
5365218822Sdim      goto write_done;
5366218822Sdim    }
5367218822Sdim
5368218822Sdim  if (fixP->fx_addsy != 0 || fixP->fx_pcrel != 0)
5369218822Sdim    return;
5370218822Sdim  else
5371218822Sdim    {
5372218822Sdim      as_warn_where (fixP->fx_file, fixP->fx_line,
5373218822Sdim		     _("type %d reloc done?\n"), (int) fixP->fx_r_type);
5374218822Sdim      goto done;
5375218822Sdim    }
5376218822Sdim
5377218822Sdimwrite_done:
5378218822Sdim  md_number_to_chars (fixpos, image, 4);
5379218822Sdim
5380218822Sdimdone:
5381218822Sdim  fixP->fx_done = 1;
5382218822Sdim}
5383218822Sdim
5384218822Sdim/* Look for a register name in the given symbol.  */
5385218822Sdim
5386218822SdimsymbolS *
5387218822Sdimmd_undefined_symbol (char *name)
5388218822Sdim{
5389218822Sdim  if (*name == '$')
5390218822Sdim    {
5391218822Sdim      int is_float = 0, num;
5392218822Sdim
5393218822Sdim      switch (*++name)
5394218822Sdim	{
5395218822Sdim	case 'f':
5396218822Sdim	  if (name[1] == 'p' && name[2] == '\0')
5397218822Sdim	    return alpha_register_table[AXP_REG_FP];
5398218822Sdim	  is_float = 32;
5399218822Sdim	  /* Fall through.  */
5400218822Sdim
5401218822Sdim	case 'r':
5402218822Sdim	  if (!ISDIGIT (*++name))
5403218822Sdim	    break;
5404218822Sdim	  /* Fall through.  */
5405218822Sdim
5406218822Sdim	case '0': case '1': case '2': case '3': case '4':
5407218822Sdim	case '5': case '6': case '7': case '8': case '9':
5408218822Sdim	  if (name[1] == '\0')
5409218822Sdim	    num = name[0] - '0';
5410218822Sdim	  else if (name[0] != '0' && ISDIGIT (name[1]) && name[2] == '\0')
5411218822Sdim	    {
5412218822Sdim	      num = (name[0] - '0') * 10 + name[1] - '0';
5413218822Sdim	      if (num >= 32)
5414218822Sdim		break;
5415218822Sdim	    }
5416218822Sdim	  else
5417218822Sdim	    break;
5418218822Sdim
5419218822Sdim	  if (!alpha_noat_on && (num + is_float) == AXP_REG_AT)
5420218822Sdim	    as_warn (_("Used $at without \".set noat\""));
5421218822Sdim	  return alpha_register_table[num + is_float];
5422218822Sdim
5423218822Sdim	case 'a':
5424218822Sdim	  if (name[1] == 't' && name[2] == '\0')
5425218822Sdim	    {
5426218822Sdim	      if (!alpha_noat_on)
5427218822Sdim		as_warn (_("Used $at without \".set noat\""));
5428218822Sdim	      return alpha_register_table[AXP_REG_AT];
5429218822Sdim	    }
5430218822Sdim	  break;
5431218822Sdim
5432218822Sdim	case 'g':
5433218822Sdim	  if (name[1] == 'p' && name[2] == '\0')
5434218822Sdim	    return alpha_register_table[alpha_gp_register];
5435218822Sdim	  break;
5436218822Sdim
5437218822Sdim	case 's':
5438218822Sdim	  if (name[1] == 'p' && name[2] == '\0')
5439218822Sdim	    return alpha_register_table[AXP_REG_SP];
5440218822Sdim	  break;
5441218822Sdim	}
5442218822Sdim    }
5443218822Sdim  return NULL;
5444218822Sdim}
5445218822Sdim
5446218822Sdim#ifdef OBJ_ECOFF
5447218822Sdim/* @@@ Magic ECOFF bits.  */
5448218822Sdim
5449218822Sdimvoid
5450218822Sdimalpha_frob_ecoff_data (void)
5451218822Sdim{
5452218822Sdim  select_gp_value ();
5453218822Sdim  /* $zero and $f31 are read-only.  */
5454218822Sdim  alpha_gprmask &= ~1;
5455218822Sdim  alpha_fprmask &= ~1;
5456218822Sdim}
5457218822Sdim#endif
5458218822Sdim
5459218822Sdim/* Hook to remember a recently defined label so that the auto-align
5460218822Sdim   code can adjust the symbol after we know what alignment will be
5461218822Sdim   required.  */
5462218822Sdim
5463218822Sdimvoid
5464218822Sdimalpha_define_label (symbolS *sym)
5465218822Sdim{
5466218822Sdim  alpha_insn_label = sym;
5467218822Sdim#ifdef OBJ_ELF
5468218822Sdim  dwarf2_emit_label (sym);
5469218822Sdim#endif
5470218822Sdim}
5471218822Sdim
5472218822Sdim/* Return true if we must always emit a reloc for a type and false if
5473218822Sdim   there is some hope of resolving it at assembly time.  */
5474218822Sdim
5475218822Sdimint
5476218822Sdimalpha_force_relocation (fixS *f)
5477218822Sdim{
5478218822Sdim  if (alpha_flag_relax)
5479218822Sdim    return 1;
5480218822Sdim
5481218822Sdim  switch (f->fx_r_type)
5482218822Sdim    {
5483218822Sdim    case BFD_RELOC_ALPHA_GPDISP_HI16:
5484218822Sdim    case BFD_RELOC_ALPHA_GPDISP_LO16:
5485218822Sdim    case BFD_RELOC_ALPHA_GPDISP:
5486218822Sdim    case BFD_RELOC_ALPHA_LITERAL:
5487218822Sdim    case BFD_RELOC_ALPHA_ELF_LITERAL:
5488218822Sdim    case BFD_RELOC_ALPHA_LITUSE:
5489218822Sdim    case BFD_RELOC_GPREL16:
5490218822Sdim    case BFD_RELOC_GPREL32:
5491218822Sdim    case BFD_RELOC_ALPHA_GPREL_HI16:
5492218822Sdim    case BFD_RELOC_ALPHA_GPREL_LO16:
5493218822Sdim    case BFD_RELOC_ALPHA_LINKAGE:
5494218822Sdim    case BFD_RELOC_ALPHA_CODEADDR:
5495218822Sdim    case BFD_RELOC_ALPHA_BRSGP:
5496218822Sdim    case BFD_RELOC_ALPHA_TLSGD:
5497218822Sdim    case BFD_RELOC_ALPHA_TLSLDM:
5498218822Sdim    case BFD_RELOC_ALPHA_GOTDTPREL16:
5499218822Sdim    case BFD_RELOC_ALPHA_DTPREL_HI16:
5500218822Sdim    case BFD_RELOC_ALPHA_DTPREL_LO16:
5501218822Sdim    case BFD_RELOC_ALPHA_DTPREL16:
5502218822Sdim    case BFD_RELOC_ALPHA_GOTTPREL16:
5503218822Sdim    case BFD_RELOC_ALPHA_TPREL_HI16:
5504218822Sdim    case BFD_RELOC_ALPHA_TPREL_LO16:
5505218822Sdim    case BFD_RELOC_ALPHA_TPREL16:
5506218822Sdim      return 1;
5507218822Sdim
5508218822Sdim    default:
5509218822Sdim      break;
5510218822Sdim    }
5511218822Sdim
5512218822Sdim  return generic_force_reloc (f);
5513218822Sdim}
5514218822Sdim
5515218822Sdim/* Return true if we can partially resolve a relocation now.  */
5516218822Sdim
5517218822Sdimint
5518218822Sdimalpha_fix_adjustable (fixS *f)
5519218822Sdim{
5520218822Sdim  /* Are there any relocation types for which we must generate a
5521218822Sdim     reloc but we can adjust the values contained within it?   */
5522218822Sdim  switch (f->fx_r_type)
5523218822Sdim    {
5524218822Sdim    case BFD_RELOC_ALPHA_GPDISP_HI16:
5525218822Sdim    case BFD_RELOC_ALPHA_GPDISP_LO16:
5526218822Sdim    case BFD_RELOC_ALPHA_GPDISP:
5527218822Sdim      return 0;
5528218822Sdim
5529218822Sdim    case BFD_RELOC_ALPHA_LITERAL:
5530218822Sdim    case BFD_RELOC_ALPHA_ELF_LITERAL:
5531218822Sdim    case BFD_RELOC_ALPHA_LITUSE:
5532218822Sdim    case BFD_RELOC_ALPHA_LINKAGE:
5533218822Sdim    case BFD_RELOC_ALPHA_CODEADDR:
5534218822Sdim      return 1;
5535218822Sdim
5536218822Sdim    case BFD_RELOC_VTABLE_ENTRY:
5537218822Sdim    case BFD_RELOC_VTABLE_INHERIT:
5538218822Sdim      return 0;
5539218822Sdim
5540218822Sdim    case BFD_RELOC_GPREL16:
5541218822Sdim    case BFD_RELOC_GPREL32:
5542218822Sdim    case BFD_RELOC_ALPHA_GPREL_HI16:
5543218822Sdim    case BFD_RELOC_ALPHA_GPREL_LO16:
5544218822Sdim    case BFD_RELOC_23_PCREL_S2:
5545218822Sdim    case BFD_RELOC_32:
5546218822Sdim    case BFD_RELOC_64:
5547218822Sdim    case BFD_RELOC_ALPHA_HINT:
5548218822Sdim      return 1;
5549218822Sdim
5550218822Sdim    case BFD_RELOC_ALPHA_TLSGD:
5551218822Sdim    case BFD_RELOC_ALPHA_TLSLDM:
5552218822Sdim    case BFD_RELOC_ALPHA_GOTDTPREL16:
5553218822Sdim    case BFD_RELOC_ALPHA_DTPREL_HI16:
5554218822Sdim    case BFD_RELOC_ALPHA_DTPREL_LO16:
5555218822Sdim    case BFD_RELOC_ALPHA_DTPREL16:
5556218822Sdim    case BFD_RELOC_ALPHA_GOTTPREL16:
5557218822Sdim    case BFD_RELOC_ALPHA_TPREL_HI16:
5558218822Sdim    case BFD_RELOC_ALPHA_TPREL_LO16:
5559218822Sdim    case BFD_RELOC_ALPHA_TPREL16:
5560218822Sdim      /* ??? No idea why we can't return a reference to .tbss+10, but
5561218822Sdim	 we're preventing this in the other assemblers.  Follow for now.  */
5562218822Sdim      return 0;
5563218822Sdim
5564218822Sdim#ifdef OBJ_ELF
5565218822Sdim    case BFD_RELOC_ALPHA_BRSGP:
5566218822Sdim      /* If we have a BRSGP reloc to a local symbol, adjust it to BRADDR and
5567218822Sdim         let it get resolved at assembly time.  */
5568218822Sdim      {
5569218822Sdim	symbolS *sym = f->fx_addsy;
5570218822Sdim	const char *name;
5571218822Sdim	int offset = 0;
5572218822Sdim
5573218822Sdim	if (generic_force_reloc (f))
5574218822Sdim	  return 0;
5575218822Sdim
5576218822Sdim	switch (S_GET_OTHER (sym) & STO_ALPHA_STD_GPLOAD)
5577218822Sdim	  {
5578218822Sdim	  case STO_ALPHA_NOPV:
5579218822Sdim	    break;
5580218822Sdim	  case STO_ALPHA_STD_GPLOAD:
5581218822Sdim	    offset = 8;
5582218822Sdim	    break;
5583218822Sdim	  default:
5584218822Sdim	    if (S_IS_LOCAL (sym))
5585218822Sdim	      name = "<local>";
5586218822Sdim	    else
5587218822Sdim	      name = S_GET_NAME (sym);
5588218822Sdim	    as_bad_where (f->fx_file, f->fx_line,
5589218822Sdim		_("!samegp reloc against symbol without .prologue: %s"),
5590218822Sdim		name);
5591218822Sdim	    break;
5592218822Sdim	  }
5593218822Sdim	f->fx_r_type = BFD_RELOC_23_PCREL_S2;
5594218822Sdim	f->fx_offset += offset;
5595218822Sdim	return 1;
5596218822Sdim      }
5597218822Sdim#endif
5598218822Sdim
5599218822Sdim    default:
5600218822Sdim      return 1;
5601218822Sdim    }
5602218822Sdim}
5603218822Sdim
5604218822Sdim/* Generate the BFD reloc to be stuck in the object file from the
5605218822Sdim   fixup used internally in the assembler.  */
5606218822Sdim
5607218822Sdimarelent *
5608218822Sdimtc_gen_reloc (asection *sec ATTRIBUTE_UNUSED,
5609218822Sdim	      fixS *fixp)
5610218822Sdim{
5611218822Sdim  arelent *reloc;
5612218822Sdim
5613218822Sdim  reloc = xmalloc (sizeof (* reloc));
5614218822Sdim  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
5615218822Sdim  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
5616218822Sdim  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
5617218822Sdim
5618218822Sdim  /* Make sure none of our internal relocations make it this far.
5619218822Sdim     They'd better have been fully resolved by this point.  */
5620218822Sdim  assert ((int) fixp->fx_r_type > 0);
5621218822Sdim
5622218822Sdim  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
5623218822Sdim  if (reloc->howto == NULL)
5624218822Sdim    {
5625218822Sdim      as_bad_where (fixp->fx_file, fixp->fx_line,
5626218822Sdim		    _("cannot represent `%s' relocation in object file"),
5627218822Sdim		    bfd_get_reloc_code_name (fixp->fx_r_type));
5628218822Sdim      return NULL;
5629218822Sdim    }
5630218822Sdim
5631218822Sdim  if (!fixp->fx_pcrel != !reloc->howto->pc_relative)
5632218822Sdim    as_fatal (_("internal error? cannot generate `%s' relocation"),
5633218822Sdim	      bfd_get_reloc_code_name (fixp->fx_r_type));
5634218822Sdim
5635218822Sdim  assert (!fixp->fx_pcrel == !reloc->howto->pc_relative);
5636218822Sdim
5637218822Sdim#ifdef OBJ_ECOFF
5638218822Sdim  if (fixp->fx_r_type == BFD_RELOC_ALPHA_LITERAL)
5639218822Sdim    /* Fake out bfd_perform_relocation. sigh.  */
5640218822Sdim    reloc->addend = -alpha_gp_value;
5641218822Sdim  else
5642218822Sdim#endif
5643218822Sdim    {
5644218822Sdim      reloc->addend = fixp->fx_offset;
5645218822Sdim#ifdef OBJ_ELF
5646218822Sdim      /* Ohhh, this is ugly.  The problem is that if this is a local global
5647218822Sdim         symbol, the relocation will entirely be performed at link time, not
5648218822Sdim         at assembly time.  bfd_perform_reloc doesn't know about this sort
5649218822Sdim         of thing, and as a result we need to fake it out here.  */
5650218822Sdim      if ((S_IS_EXTERNAL (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)
5651218822Sdim	   || (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE)
5652218822Sdim	   || (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_THREAD_LOCAL))
5653218822Sdim	  && !S_IS_COMMON (fixp->fx_addsy))
5654218822Sdim	reloc->addend -= symbol_get_bfdsym (fixp->fx_addsy)->value;
5655218822Sdim#endif
5656218822Sdim    }
5657218822Sdim
5658218822Sdim  return reloc;
5659218822Sdim}
5660218822Sdim
5661218822Sdim/* Parse a register name off of the input_line and return a register
5662218822Sdim   number.  Gets md_undefined_symbol above to do the register name
5663218822Sdim   matching for us.
5664218822Sdim
5665218822Sdim   Only called as a part of processing the ECOFF .frame directive.  */
5666218822Sdim
5667218822Sdimint
5668218822Sdimtc_get_register (int frame ATTRIBUTE_UNUSED)
5669218822Sdim{
5670218822Sdim  int framereg = AXP_REG_SP;
5671218822Sdim
5672218822Sdim  SKIP_WHITESPACE ();
5673218822Sdim  if (*input_line_pointer == '$')
5674218822Sdim    {
5675218822Sdim      char *s = input_line_pointer;
5676218822Sdim      char c = get_symbol_end ();
5677218822Sdim      symbolS *sym = md_undefined_symbol (s);
5678218822Sdim
5679218822Sdim      *strchr (s, '\0') = c;
5680218822Sdim      if (sym && (framereg = S_GET_VALUE (sym)) <= 31)
5681218822Sdim	goto found;
5682218822Sdim    }
5683218822Sdim  as_warn (_("frame reg expected, using $%d."), framereg);
5684218822Sdim
5685218822Sdimfound:
5686218822Sdim  note_gpreg (framereg);
5687218822Sdim  return framereg;
5688218822Sdim}
5689218822Sdim
5690218822Sdim/* This is called before the symbol table is processed.  In order to
5691218822Sdim   work with gcc when using mips-tfile, we must keep all local labels.
5692218822Sdim   However, in other cases, we want to discard them.  If we were
5693218822Sdim   called with -g, but we didn't see any debugging information, it may
5694218822Sdim   mean that gcc is smuggling debugging information through to
5695218822Sdim   mips-tfile, in which case we must generate all local labels.  */
5696218822Sdim
5697218822Sdim#ifdef OBJ_ECOFF
5698218822Sdim
5699218822Sdimvoid
5700218822Sdimalpha_frob_file_before_adjust (void)
5701218822Sdim{
5702218822Sdim  if (alpha_debug != 0
5703218822Sdim      && ! ecoff_debugging_seen)
5704218822Sdim    flag_keep_locals = 1;
5705218822Sdim}
5706218822Sdim
5707218822Sdim#endif /* OBJ_ECOFF */
5708218822Sdim
570933965Sjdp/* The Alpha has support for some VAX floating point types, as well as for
571033965Sjdp   IEEE floating point.  We consider IEEE to be the primary floating point
571133965Sjdp   format, and sneak in the VAX floating point support here.  */
571233965Sjdp#define md_atof vax_md_atof
571333965Sjdp#include "config/atof-vax.c"
5714