diff options
Diffstat (limited to 'binutils-2.24/gas/config/tc-alpha.c')
-rw-r--r-- | binutils-2.24/gas/config/tc-alpha.c | 6371 |
1 files changed, 0 insertions, 6371 deletions
diff --git a/binutils-2.24/gas/config/tc-alpha.c b/binutils-2.24/gas/config/tc-alpha.c deleted file mode 100644 index d020896d..00000000 --- a/binutils-2.24/gas/config/tc-alpha.c +++ /dev/null @@ -1,6371 +0,0 @@ -/* tc-alpha.c - Processor-specific code for the DEC Alpha AXP CPU. - Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. - Contributed by Carnegie Mellon University, 1993. - Written by Alessandro Forin, based on earlier gas-1.38 target CPU files. - Modified by Ken Raeburn for gas-2.x and ECOFF support. - Modified by Richard Henderson for ELF support. - Modified by Klaus K"ampf for EVAX (OpenVMS/Alpha) support. - - This file is part of GAS, the GNU Assembler. - - GAS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. - - GAS is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GAS; see the file COPYING. If not, write to the Free - Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -/* Mach Operating System - Copyright (c) 1993 Carnegie Mellon University - All Rights Reserved. - - Permission to use, copy, modify and distribute this software and its - documentation is hereby granted, provided that both the copyright - notice and this permission notice appear in all copies of the - software, derivative works or modified versions, and any portions - thereof, and that both notices appear in supporting documentation. - - CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS - CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - - Carnegie Mellon requests users of this software to return to - - Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - School of Computer Science - Carnegie Mellon University - Pittsburgh PA 15213-3890 - - any improvements or extensions that they make and grant Carnegie the - rights to redistribute these changes. */ - -#include "as.h" -#include "subsegs.h" -#include "struc-symbol.h" -#include "ecoff.h" - -#include "opcode/alpha.h" - -#ifdef OBJ_ELF -#include "elf/alpha.h" -#endif - -#ifdef OBJ_EVAX -#include "vms.h" -#include "vms/egps.h" -#endif - -#include "dwarf2dbg.h" -#include "dw2gencfi.h" -#include "safe-ctype.h" - -/* Local types. */ - -#define TOKENIZE_ERROR -1 -#define TOKENIZE_ERROR_REPORT -2 -#define MAX_INSN_FIXUPS 2 -#define MAX_INSN_ARGS 5 - -/* Used since new relocation types are introduced in this - file (DUMMY_RELOC_LITUSE_*) */ -typedef int extended_bfd_reloc_code_real_type; - -struct alpha_fixup -{ - expressionS exp; - /* bfd_reloc_code_real_type reloc; */ - extended_bfd_reloc_code_real_type reloc; -#ifdef OBJ_EVAX - /* The symbol of the item in the linkage section. */ - symbolS *xtrasym; - - /* The symbol of the procedure descriptor. */ - symbolS *procsym; -#endif -}; - -struct alpha_insn -{ - unsigned insn; - int nfixups; - struct alpha_fixup fixups[MAX_INSN_FIXUPS]; - long sequence; -}; - -enum alpha_macro_arg - { - MACRO_EOA = 1, - MACRO_IR, - MACRO_PIR, - MACRO_OPIR, - MACRO_CPIR, - MACRO_FPR, - MACRO_EXP - }; - -struct alpha_macro -{ - const char *name; - void (*emit) (const expressionS *, int, const void *); - const void * arg; - enum alpha_macro_arg argsets[16]; -}; - -/* Extra expression types. */ - -#define O_pregister O_md1 /* O_register, in parentheses. */ -#define O_cpregister O_md2 /* + a leading comma. */ - -/* The alpha_reloc_op table below depends on the ordering of these. */ -#define O_literal O_md3 /* !literal relocation. */ -#define O_lituse_addr O_md4 /* !lituse_addr relocation. */ -#define O_lituse_base O_md5 /* !lituse_base relocation. */ -#define O_lituse_bytoff O_md6 /* !lituse_bytoff relocation. */ -#define O_lituse_jsr O_md7 /* !lituse_jsr relocation. */ -#define O_lituse_tlsgd O_md8 /* !lituse_tlsgd relocation. */ -#define O_lituse_tlsldm O_md9 /* !lituse_tlsldm relocation. */ -#define O_lituse_jsrdirect O_md10 /* !lituse_jsrdirect relocation. */ -#define O_gpdisp O_md11 /* !gpdisp relocation. */ -#define O_gprelhigh O_md12 /* !gprelhigh relocation. */ -#define O_gprellow O_md13 /* !gprellow relocation. */ -#define O_gprel O_md14 /* !gprel relocation. */ -#define O_samegp O_md15 /* !samegp relocation. */ -#define O_tlsgd O_md16 /* !tlsgd relocation. */ -#define O_tlsldm O_md17 /* !tlsldm relocation. */ -#define O_gotdtprel O_md18 /* !gotdtprel relocation. */ -#define O_dtprelhi O_md19 /* !dtprelhi relocation. */ -#define O_dtprello O_md20 /* !dtprello relocation. */ -#define O_dtprel O_md21 /* !dtprel relocation. */ -#define O_gottprel O_md22 /* !gottprel relocation. */ -#define O_tprelhi O_md23 /* !tprelhi relocation. */ -#define O_tprello O_md24 /* !tprello relocation. */ -#define O_tprel O_md25 /* !tprel relocation. */ - -#define DUMMY_RELOC_LITUSE_ADDR (BFD_RELOC_UNUSED + 1) -#define DUMMY_RELOC_LITUSE_BASE (BFD_RELOC_UNUSED + 2) -#define DUMMY_RELOC_LITUSE_BYTOFF (BFD_RELOC_UNUSED + 3) -#define DUMMY_RELOC_LITUSE_JSR (BFD_RELOC_UNUSED + 4) -#define DUMMY_RELOC_LITUSE_TLSGD (BFD_RELOC_UNUSED + 5) -#define DUMMY_RELOC_LITUSE_TLSLDM (BFD_RELOC_UNUSED + 6) -#define DUMMY_RELOC_LITUSE_JSRDIRECT (BFD_RELOC_UNUSED + 7) - -#define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_tprel) - -/* Macros for extracting the type and number of encoded register tokens. */ - -#define is_ir_num(x) (((x) & 32) == 0) -#define is_fpr_num(x) (((x) & 32) != 0) -#define regno(x) ((x) & 31) - -/* Something odd inherited from the old assembler. */ - -#define note_gpreg(R) (alpha_gprmask |= (1 << (R))) -#define note_fpreg(R) (alpha_fprmask |= (1 << (R))) - -/* Predicates for 16- and 32-bit ranges */ -/* XXX: The non-shift version appears to trigger a compiler bug when - cross-assembling from x86 w/ gcc 2.7.2. */ - -#if 1 -#define range_signed_16(x) \ - (((offsetT) (x) >> 15) == 0 || ((offsetT) (x) >> 15) == -1) -#define range_signed_32(x) \ - (((offsetT) (x) >> 31) == 0 || ((offsetT) (x) >> 31) == -1) -#else -#define range_signed_16(x) ((offsetT) (x) >= -(offsetT) 0x8000 && \ - (offsetT) (x) <= (offsetT) 0x7FFF) -#define range_signed_32(x) ((offsetT) (x) >= -(offsetT) 0x80000000 && \ - (offsetT) (x) <= (offsetT) 0x7FFFFFFF) -#endif - -/* Macros for sign extending from 16- and 32-bits. */ -/* XXX: The cast macros will work on all the systems that I care about, - but really a predicate should be found to use the non-cast forms. */ - -#if 1 -#define sign_extend_16(x) ((short) (x)) -#define sign_extend_32(x) ((int) (x)) -#else -#define sign_extend_16(x) ((offsetT) (((x) & 0xFFFF) ^ 0x8000) - 0x8000) -#define sign_extend_32(x) ((offsetT) (((x) & 0xFFFFFFFF) \ - ^ 0x80000000) - 0x80000000) -#endif - -/* Macros to build tokens. */ - -#define set_tok_reg(t, r) (memset (&(t), 0, sizeof (t)), \ - (t).X_op = O_register, \ - (t).X_add_number = (r)) -#define set_tok_preg(t, r) (memset (&(t), 0, sizeof (t)), \ - (t).X_op = O_pregister, \ - (t).X_add_number = (r)) -#define set_tok_cpreg(t, r) (memset (&(t), 0, sizeof (t)), \ - (t).X_op = O_cpregister, \ - (t).X_add_number = (r)) -#define set_tok_freg(t, r) (memset (&(t), 0, sizeof (t)), \ - (t).X_op = O_register, \ - (t).X_add_number = (r) + 32) -#define set_tok_sym(t, s, a) (memset (&(t), 0, sizeof (t)), \ - (t).X_op = O_symbol, \ - (t).X_add_symbol = (s), \ - (t).X_add_number = (a)) -#define set_tok_const(t, n) (memset (&(t), 0, sizeof (t)), \ - (t).X_op = O_constant, \ - (t).X_add_number = (n)) - -/* Generic assembler global variables which must be defined by all - targets. */ - -/* Characters which always start a comment. */ -const char comment_chars[] = "#"; - -/* Characters which start a comment at the beginning of a line. */ -const char line_comment_chars[] = "#"; - -/* Characters which may be used to separate multiple commands on a - single line. */ -const char line_separator_chars[] = ";"; - -/* Characters which are used to indicate an exponent in a floating - point number. */ -const char EXP_CHARS[] = "eE"; - -/* Characters which mean that a number is a floating point constant, - as in 0d1.0. */ -/* XXX: Do all of these really get used on the alpha?? */ -char FLT_CHARS[] = "rRsSfFdDxXpP"; - -#ifdef OBJ_EVAX -const char *md_shortopts = "Fm:g+1h:HG:"; -#else -const char *md_shortopts = "Fm:gG:"; -#endif - -struct option md_longopts[] = - { -#define OPTION_32ADDR (OPTION_MD_BASE) - { "32addr", no_argument, NULL, OPTION_32ADDR }, -#define OPTION_RELAX (OPTION_32ADDR + 1) - { "relax", no_argument, NULL, OPTION_RELAX }, -#ifdef OBJ_ELF -#define OPTION_MDEBUG (OPTION_RELAX + 1) -#define OPTION_NO_MDEBUG (OPTION_MDEBUG + 1) - { "mdebug", no_argument, NULL, OPTION_MDEBUG }, - { "no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG }, -#endif -#ifdef OBJ_EVAX -#define OPTION_REPLACE (OPTION_RELAX + 1) -#define OPTION_NOREPLACE (OPTION_REPLACE+1) - { "replace", no_argument, NULL, OPTION_REPLACE }, - { "noreplace", no_argument, NULL, OPTION_NOREPLACE }, -#endif - { NULL, no_argument, NULL, 0 } - }; - -size_t md_longopts_size = sizeof (md_longopts); - -#ifdef OBJ_EVAX -#define AXP_REG_R0 0 -#define AXP_REG_R16 16 -#define AXP_REG_R17 17 -#undef AXP_REG_T9 -#define AXP_REG_T9 22 -#undef AXP_REG_T10 -#define AXP_REG_T10 23 -#undef AXP_REG_T11 -#define AXP_REG_T11 24 -#undef AXP_REG_T12 -#define AXP_REG_T12 25 -#define AXP_REG_AI 25 -#undef AXP_REG_FP -#define AXP_REG_FP 29 - -#undef AXP_REG_GP -#define AXP_REG_GP AXP_REG_PV - -#endif /* OBJ_EVAX */ - -/* The cpu for which we are generating code. */ -static unsigned alpha_target = AXP_OPCODE_BASE; -static const char *alpha_target_name = "<all>"; - -/* The hash table of instruction opcodes. */ -static struct hash_control *alpha_opcode_hash; - -/* The hash table of macro opcodes. */ -static struct hash_control *alpha_macro_hash; - -#ifdef OBJ_ECOFF -/* The $gp relocation symbol. */ -static symbolS *alpha_gp_symbol; - -/* XXX: what is this, and why is it exported? */ -valueT alpha_gp_value; -#endif - -/* The current $gp register. */ -static int alpha_gp_register = AXP_REG_GP; - -/* A table of the register symbols. */ -static symbolS *alpha_register_table[64]; - -/* Constant sections, or sections of constants. */ -#ifdef OBJ_ECOFF -static segT alpha_lita_section; -#endif -#ifdef OBJ_EVAX -segT alpha_link_section; -#endif -#ifndef OBJ_EVAX -static segT alpha_lit8_section; -#endif - -/* Symbols referring to said sections. */ -#ifdef OBJ_ECOFF -static symbolS *alpha_lita_symbol; -#endif -#ifdef OBJ_EVAX -static symbolS *alpha_link_symbol; -#endif -#ifndef OBJ_EVAX -static symbolS *alpha_lit8_symbol; -#endif - -/* Literal for .litX+0x8000 within .lita. */ -#ifdef OBJ_ECOFF -static offsetT alpha_lit8_literal; -#endif - -/* Is the assembler not allowed to use $at? */ -static int alpha_noat_on = 0; - -/* Are macros enabled? */ -static int alpha_macros_on = 1; - -/* Are floats disabled? */ -static int alpha_nofloats_on = 0; - -/* Are addresses 32 bit? */ -static int alpha_addr32_on = 0; - -/* Symbol labelling the current insn. When the Alpha gas sees - foo: - .quad 0 - and the section happens to not be on an eight byte boundary, it - will align both the symbol and the .quad to an eight byte boundary. */ -static symbolS *alpha_insn_label; -#if defined(OBJ_ELF) || defined (OBJ_EVAX) -static symbolS *alpha_prologue_label; -#endif - -#ifdef OBJ_EVAX -/* Symbol associate with the current jsr instruction. */ -static symbolS *alpha_linkage_symbol; -#endif - -/* Whether we should automatically align data generation pseudo-ops. - .align 0 will turn this off. */ -static int alpha_auto_align_on = 1; - -/* The known current alignment of the current section. */ -static int alpha_current_align; - -/* These are exported to ECOFF code. */ -unsigned long alpha_gprmask, alpha_fprmask; - -/* Whether the debugging option was seen. */ -static int alpha_debug; - -#ifdef OBJ_ELF -/* Whether we are emitting an mdebug section. */ -int alpha_flag_mdebug = -1; -#endif - -#ifdef OBJ_EVAX -/* Whether to perform the VMS procedure call optimization. */ -int alpha_flag_replace = 1; -#endif - -/* Don't fully resolve relocations, allowing code movement in the linker. */ -static int alpha_flag_relax; - -/* What value to give to bfd_set_gp_size. */ -static int g_switch_value = 8; - -#ifdef OBJ_EVAX -/* Collect information about current procedure here. */ -struct alpha_evax_procs -{ - symbolS *symbol; /* Proc pdesc symbol. */ - int pdsckind; - int framereg; /* Register for frame pointer. */ - int framesize; /* Size of frame. */ - int rsa_offset; - int ra_save; - int fp_save; - long imask; - long fmask; - int type; - int prologue; - symbolS *handler; - int handler_data; -}; - -/* Linked list of .linkage fixups. */ -struct alpha_linkage_fixups *alpha_linkage_fixup_root; -static struct alpha_linkage_fixups *alpha_linkage_fixup_tail; - -/* Current procedure descriptor. */ -static struct alpha_evax_procs *alpha_evax_proc; -static struct alpha_evax_procs alpha_evax_proc_data; - -static int alpha_flag_hash_long_names = 0; /* -+ */ -static int alpha_flag_show_after_trunc = 0; /* -H */ - -/* If the -+ switch is given, then a hash is appended to any name that is - longer than 64 characters, else longer symbol names are truncated. */ - -#endif - -#ifdef RELOC_OP_P -/* A table to map the spelling of a relocation operand into an appropriate - bfd_reloc_code_real_type type. The table is assumed to be ordered such - that op-O_literal indexes into it. */ - -#define ALPHA_RELOC_TABLE(op) \ -(&alpha_reloc_op[ ((!USER_RELOC_P (op)) \ - ? (abort (), 0) \ - : (int) (op) - (int) O_literal) ]) - -#define DEF(NAME, RELOC, REQ, ALLOW) \ - { #NAME, sizeof(#NAME)-1, O_##NAME, RELOC, REQ, ALLOW} - -static const struct alpha_reloc_op_tag -{ - const char *name; /* String to lookup. */ - size_t length; /* Size of the string. */ - operatorT op; /* Which operator to use. */ - extended_bfd_reloc_code_real_type reloc; - unsigned int require_seq : 1; /* Require a sequence number. */ - unsigned int allow_seq : 1; /* Allow a sequence number. */ -} -alpha_reloc_op[] = -{ - DEF (literal, BFD_RELOC_ALPHA_ELF_LITERAL, 0, 1), - DEF (lituse_addr, DUMMY_RELOC_LITUSE_ADDR, 1, 1), - DEF (lituse_base, DUMMY_RELOC_LITUSE_BASE, 1, 1), - DEF (lituse_bytoff, DUMMY_RELOC_LITUSE_BYTOFF, 1, 1), - DEF (lituse_jsr, DUMMY_RELOC_LITUSE_JSR, 1, 1), - DEF (lituse_tlsgd, DUMMY_RELOC_LITUSE_TLSGD, 1, 1), - DEF (lituse_tlsldm, DUMMY_RELOC_LITUSE_TLSLDM, 1, 1), - DEF (lituse_jsrdirect, DUMMY_RELOC_LITUSE_JSRDIRECT, 1, 1), - DEF (gpdisp, BFD_RELOC_ALPHA_GPDISP, 1, 1), - DEF (gprelhigh, BFD_RELOC_ALPHA_GPREL_HI16, 0, 0), - DEF (gprellow, BFD_RELOC_ALPHA_GPREL_LO16, 0, 0), - DEF (gprel, BFD_RELOC_GPREL16, 0, 0), - DEF (samegp, BFD_RELOC_ALPHA_BRSGP, 0, 0), - DEF (tlsgd, BFD_RELOC_ALPHA_TLSGD, 0, 1), - DEF (tlsldm, BFD_RELOC_ALPHA_TLSLDM, 0, 1), - DEF (gotdtprel, BFD_RELOC_ALPHA_GOTDTPREL16, 0, 0), - DEF (dtprelhi, BFD_RELOC_ALPHA_DTPREL_HI16, 0, 0), - DEF (dtprello, BFD_RELOC_ALPHA_DTPREL_LO16, 0, 0), - DEF (dtprel, BFD_RELOC_ALPHA_DTPREL16, 0, 0), - DEF (gottprel, BFD_RELOC_ALPHA_GOTTPREL16, 0, 0), - DEF (tprelhi, BFD_RELOC_ALPHA_TPREL_HI16, 0, 0), - DEF (tprello, BFD_RELOC_ALPHA_TPREL_LO16, 0, 0), - DEF (tprel, BFD_RELOC_ALPHA_TPREL16, 0, 0), -}; - -#undef DEF - -static const int alpha_num_reloc_op - = sizeof (alpha_reloc_op) / sizeof (*alpha_reloc_op); -#endif /* RELOC_OP_P */ - -/* Maximum # digits needed to hold the largest sequence #. */ -#define ALPHA_RELOC_DIGITS 25 - -/* Structure to hold explicit sequence information. */ -struct alpha_reloc_tag -{ - fixS *master; /* The literal reloc. */ -#ifdef OBJ_EVAX - struct symbol *sym; /* Linkage section item symbol. */ - struct symbol *psym; /* Pdesc symbol. */ -#endif - fixS *slaves; /* Head of linked list of lituses. */ - segT segment; /* Segment relocs are in or undefined_section. */ - long sequence; /* Sequence #. */ - unsigned n_master; /* # of literals. */ - unsigned n_slaves; /* # of lituses. */ - unsigned saw_tlsgd : 1; /* True if ... */ - unsigned saw_tlsldm : 1; - unsigned saw_lu_tlsgd : 1; - unsigned saw_lu_tlsldm : 1; - unsigned multi_section_p : 1; /* True if more than one section was used. */ - char string[1]; /* Printable form of sequence to hash with. */ -}; - -/* Hash table to link up literals with the appropriate lituse. */ -static struct hash_control *alpha_literal_hash; - -/* Sequence numbers for internal use by macros. */ -static long next_sequence_num = -1; - -/* A table of CPU names and opcode sets. */ - -static const struct cpu_type -{ - const char *name; - unsigned flags; -} -cpu_types[] = -{ - /* Ad hoc convention: cpu number gets palcode, process code doesn't. - This supports usage under DU 4.0b that does ".arch ev4", and - usage in MILO that does -m21064. Probably something more - specific like -m21064-pal should be used, but oh well. */ - - { "21064", AXP_OPCODE_BASE|AXP_OPCODE_EV4 }, - { "21064a", AXP_OPCODE_BASE|AXP_OPCODE_EV4 }, - { "21066", AXP_OPCODE_BASE|AXP_OPCODE_EV4 }, - { "21068", AXP_OPCODE_BASE|AXP_OPCODE_EV4 }, - { "21164", AXP_OPCODE_BASE|AXP_OPCODE_EV5 }, - { "21164a", AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX }, - { "21164pc", (AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX - |AXP_OPCODE_MAX) }, - { "21264", (AXP_OPCODE_BASE|AXP_OPCODE_EV6|AXP_OPCODE_BWX - |AXP_OPCODE_MAX|AXP_OPCODE_CIX) }, - { "21264a", (AXP_OPCODE_BASE|AXP_OPCODE_EV6|AXP_OPCODE_BWX - |AXP_OPCODE_MAX|AXP_OPCODE_CIX) }, - { "21264b", (AXP_OPCODE_BASE|AXP_OPCODE_EV6|AXP_OPCODE_BWX - |AXP_OPCODE_MAX|AXP_OPCODE_CIX) }, - - { "ev4", AXP_OPCODE_BASE }, - { "ev45", AXP_OPCODE_BASE }, - { "lca45", AXP_OPCODE_BASE }, - { "ev5", AXP_OPCODE_BASE }, - { "ev56", AXP_OPCODE_BASE|AXP_OPCODE_BWX }, - { "pca56", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX }, - { "ev6", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX|AXP_OPCODE_CIX }, - { "ev67", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX|AXP_OPCODE_CIX }, - { "ev68", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX|AXP_OPCODE_CIX }, - - { "all", AXP_OPCODE_BASE }, - { 0, 0 } -}; - -/* Some instruction sets indexed by lg(size). */ -static const char * const sextX_op[] = { "sextb", "sextw", "sextl", NULL }; -static const char * const insXl_op[] = { "insbl", "inswl", "insll", "insql" }; -static const char * const insXh_op[] = { NULL, "inswh", "inslh", "insqh" }; -static const char * const extXl_op[] = { "extbl", "extwl", "extll", "extql" }; -static const char * const extXh_op[] = { NULL, "extwh", "extlh", "extqh" }; -static const char * const mskXl_op[] = { "mskbl", "mskwl", "mskll", "mskql" }; -static const char * const mskXh_op[] = { NULL, "mskwh", "msklh", "mskqh" }; -static const char * const stX_op[] = { "stb", "stw", "stl", "stq" }; -static const char * const ldXu_op[] = { "ldbu", "ldwu", NULL, NULL }; - -static void assemble_insn (const struct alpha_opcode *, const expressionS *, int, struct alpha_insn *, extended_bfd_reloc_code_real_type); -static void emit_insn (struct alpha_insn *); -static void assemble_tokens (const char *, const expressionS *, int, int); -#ifdef OBJ_EVAX -static char *s_alpha_section_name (void); -static symbolS *add_to_link_pool (symbolS *, offsetT); -#endif - -static struct alpha_reloc_tag * -get_alpha_reloc_tag (long sequence) -{ - char buffer[ALPHA_RELOC_DIGITS]; - struct alpha_reloc_tag *info; - - sprintf (buffer, "!%ld", sequence); - - info = (struct alpha_reloc_tag *) hash_find (alpha_literal_hash, buffer); - if (! info) - { - size_t len = strlen (buffer); - const char *errmsg; - - info = (struct alpha_reloc_tag *) - xcalloc (sizeof (struct alpha_reloc_tag) + len, 1); - - info->segment = now_seg; - info->sequence = sequence; - strcpy (info->string, buffer); - errmsg = hash_insert (alpha_literal_hash, info->string, (void *) info); - if (errmsg) - as_fatal ("%s", errmsg); -#ifdef OBJ_EVAX - info->sym = 0; - info->psym = 0; -#endif - } - - return info; -} - -#ifndef OBJ_EVAX - -static void -alpha_adjust_relocs (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - void * ptr ATTRIBUTE_UNUSED) -{ - segment_info_type *seginfo = seg_info (sec); - fixS **prevP; - fixS *fixp; - fixS *next; - fixS *slave; - - /* If seginfo is NULL, we did not create this section; don't do - anything with it. By using a pointer to a pointer, we can update - the links in place. */ - if (seginfo == NULL) - return; - - /* If there are no relocations, skip the section. */ - if (! seginfo->fix_root) - return; - - /* First rebuild the fixup chain without the explicit lituse and - gpdisp_lo16 relocs. */ - prevP = &seginfo->fix_root; - for (fixp = seginfo->fix_root; fixp; fixp = next) - { - next = fixp->fx_next; - fixp->fx_next = (fixS *) 0; - - switch (fixp->fx_r_type) - { - case BFD_RELOC_ALPHA_LITUSE: - if (fixp->tc_fix_data.info->n_master == 0) - as_bad_where (fixp->fx_file, fixp->fx_line, - _("No !literal!%ld was found"), - fixp->tc_fix_data.info->sequence); -#ifdef RELOC_OP_P - if (fixp->fx_offset == LITUSE_ALPHA_TLSGD) - { - if (! fixp->tc_fix_data.info->saw_tlsgd) - as_bad_where (fixp->fx_file, fixp->fx_line, - _("No !tlsgd!%ld was found"), - fixp->tc_fix_data.info->sequence); - } - else if (fixp->fx_offset == LITUSE_ALPHA_TLSLDM) - { - if (! fixp->tc_fix_data.info->saw_tlsldm) - as_bad_where (fixp->fx_file, fixp->fx_line, - _("No !tlsldm!%ld was found"), - fixp->tc_fix_data.info->sequence); - } -#endif - break; - - case BFD_RELOC_ALPHA_GPDISP_LO16: - if (fixp->tc_fix_data.info->n_master == 0) - as_bad_where (fixp->fx_file, fixp->fx_line, - _("No ldah !gpdisp!%ld was found"), - fixp->tc_fix_data.info->sequence); - break; - - case BFD_RELOC_ALPHA_ELF_LITERAL: - if (fixp->tc_fix_data.info - && (fixp->tc_fix_data.info->saw_tlsgd - || fixp->tc_fix_data.info->saw_tlsldm)) - break; - /* FALLTHRU */ - - default: - *prevP = fixp; - prevP = &fixp->fx_next; - break; - } - } - - /* Go back and re-chain dependent relocations. They are currently - linked through the next_reloc field in reverse order, so as we - go through the next_reloc chain, we effectively reverse the chain - once again. - - Except if there is more than one !literal for a given sequence - number. In that case, the programmer and/or compiler is not sure - how control flows from literal to lituse, and we can't be sure to - get the relaxation correct. - - ??? Well, actually we could, if there are enough lituses such that - we can make each literal have at least one of each lituse type - present. Not implemented. - - Also suppress the optimization if the !literals/!lituses are spread - in different segments. This can happen with "intersting" uses of - inline assembly; examples are present in the Linux kernel semaphores. */ - - for (fixp = seginfo->fix_root; fixp; fixp = next) - { - next = fixp->fx_next; - switch (fixp->fx_r_type) - { - case BFD_RELOC_ALPHA_TLSGD: - case BFD_RELOC_ALPHA_TLSLDM: - if (!fixp->tc_fix_data.info) - break; - if (fixp->tc_fix_data.info->n_master == 0) - break; - else if (fixp->tc_fix_data.info->n_master > 1) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("too many !literal!%ld for %s"), - fixp->tc_fix_data.info->sequence, - (fixp->fx_r_type == BFD_RELOC_ALPHA_TLSGD - ? "!tlsgd" : "!tlsldm")); - break; - } - - fixp->tc_fix_data.info->master->fx_next = fixp->fx_next; - fixp->fx_next = fixp->tc_fix_data.info->master; - fixp = fixp->fx_next; - /* Fall through. */ - - case BFD_RELOC_ALPHA_ELF_LITERAL: - if (fixp->tc_fix_data.info - && fixp->tc_fix_data.info->n_master == 1 - && ! fixp->tc_fix_data.info->multi_section_p) - { - for (slave = fixp->tc_fix_data.info->slaves; - slave != (fixS *) 0; - slave = slave->tc_fix_data.next_reloc) - { - slave->fx_next = fixp->fx_next; - fixp->fx_next = slave; - } - } - break; - - case BFD_RELOC_ALPHA_GPDISP_HI16: - if (fixp->tc_fix_data.info->n_slaves == 0) - as_bad_where (fixp->fx_file, fixp->fx_line, - _("No lda !gpdisp!%ld was found"), - fixp->tc_fix_data.info->sequence); - else - { - slave = fixp->tc_fix_data.info->slaves; - slave->fx_next = next; - fixp->fx_next = slave; - } - break; - - default: - break; - } - } -} - -/* Before the relocations are written, reorder them, so that user - supplied !lituse relocations follow the appropriate !literal - relocations, and similarly for !gpdisp relocations. */ - -void -alpha_before_fix (void) -{ - if (alpha_literal_hash) - bfd_map_over_sections (stdoutput, alpha_adjust_relocs, NULL); -} - -#endif - -#ifdef DEBUG_ALPHA -static void -debug_exp (expressionS tok[], int ntok) -{ - int i; - - fprintf (stderr, "debug_exp: %d tokens", ntok); - for (i = 0; i < ntok; i++) - { - expressionS *t = &tok[i]; - const char *name; - - switch (t->X_op) - { - default: name = "unknown"; break; - case O_illegal: name = "O_illegal"; break; - case O_absent: name = "O_absent"; break; - case O_constant: name = "O_constant"; break; - case O_symbol: name = "O_symbol"; break; - case O_symbol_rva: name = "O_symbol_rva"; break; - case O_register: name = "O_register"; break; - case O_big: name = "O_big"; break; - case O_uminus: name = "O_uminus"; break; - case O_bit_not: name = "O_bit_not"; break; - case O_logical_not: name = "O_logical_not"; break; - case O_multiply: name = "O_multiply"; break; - case O_divide: name = "O_divide"; break; - case O_modulus: name = "O_modulus"; break; - case O_left_shift: name = "O_left_shift"; break; - case O_right_shift: name = "O_right_shift"; break; - case O_bit_inclusive_or: name = "O_bit_inclusive_or"; break; - case O_bit_or_not: name = "O_bit_or_not"; break; - case O_bit_exclusive_or: name = "O_bit_exclusive_or"; break; - case O_bit_and: name = "O_bit_and"; break; - case O_add: name = "O_add"; break; - case O_subtract: name = "O_subtract"; break; - case O_eq: name = "O_eq"; break; - case O_ne: name = "O_ne"; break; - case O_lt: name = "O_lt"; break; - case O_le: name = "O_le"; break; - case O_ge: name = "O_ge"; break; - case O_gt: name = "O_gt"; break; - case O_logical_and: name = "O_logical_and"; break; - case O_logical_or: name = "O_logical_or"; break; - case O_index: name = "O_index"; break; - case O_pregister: name = "O_pregister"; break; - case O_cpregister: name = "O_cpregister"; break; - case O_literal: name = "O_literal"; break; - case O_lituse_addr: name = "O_lituse_addr"; break; - case O_lituse_base: name = "O_lituse_base"; break; - case O_lituse_bytoff: name = "O_lituse_bytoff"; break; - case O_lituse_jsr: name = "O_lituse_jsr"; break; - case O_lituse_tlsgd: name = "O_lituse_tlsgd"; break; - case O_lituse_tlsldm: name = "O_lituse_tlsldm"; break; - case O_lituse_jsrdirect: name = "O_lituse_jsrdirect"; break; - case O_gpdisp: name = "O_gpdisp"; break; - case O_gprelhigh: name = "O_gprelhigh"; break; - case O_gprellow: name = "O_gprellow"; break; - case O_gprel: name = "O_gprel"; break; - case O_samegp: name = "O_samegp"; break; - case O_tlsgd: name = "O_tlsgd"; break; - case O_tlsldm: name = "O_tlsldm"; break; - case O_gotdtprel: name = "O_gotdtprel"; break; - case O_dtprelhi: name = "O_dtprelhi"; break; - case O_dtprello: name = "O_dtprello"; break; - case O_dtprel: name = "O_dtprel"; break; - case O_gottprel: name = "O_gottprel"; break; - case O_tprelhi: name = "O_tprelhi"; break; - case O_tprello: name = "O_tprello"; break; - case O_tprel: name = "O_tprel"; break; - } - - fprintf (stderr, ", %s(%s, %s, %d)", name, - (t->X_add_symbol) ? S_GET_NAME (t->X_add_symbol) : "--", - (t->X_op_symbol) ? S_GET_NAME (t->X_op_symbol) : "--", - (int) t->X_add_number); - } - fprintf (stderr, "\n"); - fflush (stderr); -} -#endif - -/* Parse the arguments to an opcode. */ - -static int -tokenize_arguments (char *str, - expressionS tok[], - int ntok) -{ - expressionS *end_tok = tok + ntok; - char *old_input_line_pointer; - int saw_comma = 0, saw_arg = 0; -#ifdef DEBUG_ALPHA - expressionS *orig_tok = tok; -#endif -#ifdef RELOC_OP_P - char *p; - const struct alpha_reloc_op_tag *r; - int c, i; - size_t len; - int reloc_found_p = 0; -#endif - - memset (tok, 0, sizeof (*tok) * ntok); - - /* Save and restore input_line_pointer around this function. */ - old_input_line_pointer = input_line_pointer; - input_line_pointer = str; - -#ifdef RELOC_OP_P - /* ??? Wrest control of ! away from the regular expression parser. */ - is_end_of_line[(unsigned char) '!'] = 1; -#endif - - while (tok < end_tok && *input_line_pointer) - { - SKIP_WHITESPACE (); - switch (*input_line_pointer) - { - case '\0': - goto fini; - -#ifdef RELOC_OP_P - case '!': - /* A relocation operand can be placed after the normal operand on an - assembly language statement, and has the following form: - !relocation_type!sequence_number. */ - if (reloc_found_p) - { - /* Only support one relocation op per insn. */ - as_bad (_("More than one relocation op per insn")); - goto err_report; - } - - if (!saw_arg) - goto err; - - ++input_line_pointer; - SKIP_WHITESPACE (); - p = input_line_pointer; - c = get_symbol_end (); - - /* Parse !relocation_type. */ - len = input_line_pointer - p; - if (len == 0) - { - as_bad (_("No relocation operand")); - goto err_report; - } - - r = &alpha_reloc_op[0]; - for (i = alpha_num_reloc_op - 1; i >= 0; i--, r++) - if (len == r->length && memcmp (p, r->name, len) == 0) - break; - if (i < 0) - { - as_bad (_("Unknown relocation operand: !%s"), p); - goto err_report; - } - - *input_line_pointer = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != '!') - { - if (r->require_seq) - { - as_bad (_("no sequence number after !%s"), p); - goto err_report; - } - - tok->X_add_number = 0; - } - else - { - if (! r->allow_seq) - { - as_bad (_("!%s does not use a sequence number"), p); - goto err_report; - } - - input_line_pointer++; - - /* Parse !sequence_number. */ - expression (tok); - if (tok->X_op != O_constant || tok->X_add_number <= 0) - { - as_bad (_("Bad sequence number: !%s!%s"), - r->name, input_line_pointer); - goto err_report; - } - } - - tok->X_op = r->op; - reloc_found_p = 1; - ++tok; - break; -#endif /* RELOC_OP_P */ - - case ',': - ++input_line_pointer; - if (saw_comma || !saw_arg) - goto err; - saw_comma = 1; - break; - - case '(': - { - char *hold = input_line_pointer++; - - /* First try for parenthesized register ... */ - expression (tok); - if (*input_line_pointer == ')' && tok->X_op == O_register) - { - tok->X_op = (saw_comma ? O_cpregister : O_pregister); - saw_comma = 0; - saw_arg = 1; - ++input_line_pointer; - ++tok; - break; - } - - /* ... then fall through to plain expression. */ - input_line_pointer = hold; - } - - default: - if (saw_arg && !saw_comma) - goto err; - - expression (tok); - if (tok->X_op == O_illegal || tok->X_op == O_absent) - goto err; - - saw_comma = 0; - saw_arg = 1; - ++tok; - break; - } - } - -fini: - if (saw_comma) - goto err; - input_line_pointer = old_input_line_pointer; - -#ifdef DEBUG_ALPHA - debug_exp (orig_tok, ntok - (end_tok - tok)); -#endif -#ifdef RELOC_OP_P - is_end_of_line[(unsigned char) '!'] = 0; -#endif - - return ntok - (end_tok - tok); - -err: -#ifdef RELOC_OP_P - is_end_of_line[(unsigned char) '!'] = 0; -#endif - input_line_pointer = old_input_line_pointer; - return TOKENIZE_ERROR; - -#ifdef RELOC_OP_P -err_report: - is_end_of_line[(unsigned char) '!'] = 0; -#endif - input_line_pointer = old_input_line_pointer; - return TOKENIZE_ERROR_REPORT; -} - -/* Search forward through all variants of an opcode looking for a - syntax match. */ - -static const struct alpha_opcode * -find_opcode_match (const struct alpha_opcode *first_opcode, - const expressionS *tok, - int *pntok, - int *pcpumatch) -{ - const struct alpha_opcode *opcode = first_opcode; - int ntok = *pntok; - int got_cpu_match = 0; - - do - { - const unsigned char *opidx; - int tokidx = 0; - - /* Don't match opcodes that don't exist on this architecture. */ - if (!(opcode->flags & alpha_target)) - goto match_failed; - - got_cpu_match = 1; - - for (opidx = opcode->operands; *opidx; ++opidx) - { - const struct alpha_operand *operand = &alpha_operands[*opidx]; - - /* Only take input from real operands. */ - if (operand->flags & AXP_OPERAND_FAKE) - continue; - - /* When we expect input, make sure we have it. */ - if (tokidx >= ntok) - { - if ((operand->flags & AXP_OPERAND_OPTIONAL_MASK) == 0) - goto match_failed; - continue; - } - - /* Match operand type with expression type. */ - switch (operand->flags & AXP_OPERAND_TYPECHECK_MASK) - { - case AXP_OPERAND_IR: - if (tok[tokidx].X_op != O_register - || !is_ir_num (tok[tokidx].X_add_number)) - goto match_failed; - break; - case AXP_OPERAND_FPR: - if (tok[tokidx].X_op != O_register - || !is_fpr_num (tok[tokidx].X_add_number)) - goto match_failed; - break; - case AXP_OPERAND_IR | AXP_OPERAND_PARENS: - if (tok[tokidx].X_op != O_pregister - || !is_ir_num (tok[tokidx].X_add_number)) - goto match_failed; - break; - case AXP_OPERAND_IR | AXP_OPERAND_PARENS | AXP_OPERAND_COMMA: - if (tok[tokidx].X_op != O_cpregister - || !is_ir_num (tok[tokidx].X_add_number)) - goto match_failed; - break; - - case AXP_OPERAND_RELATIVE: - case AXP_OPERAND_SIGNED: - case AXP_OPERAND_UNSIGNED: - switch (tok[tokidx].X_op) - { - case O_illegal: - case O_absent: - case O_register: - case O_pregister: - case O_cpregister: - goto match_failed; - - default: - break; - } - break; - - default: - /* Everything else should have been fake. */ - abort (); - } - ++tokidx; - } - - /* Possible match -- did we use all of our input? */ - if (tokidx == ntok) - { - *pntok = ntok; - return opcode; - } - - match_failed:; - } - while (++opcode - alpha_opcodes < (int) alpha_num_opcodes - && !strcmp (opcode->name, first_opcode->name)); - - if (*pcpumatch) - *pcpumatch = got_cpu_match; - - return NULL; -} - -/* Given an opcode name and a pre-tokenized set of arguments, assemble - the insn, but do not emit it. - - Note that this implies no macros allowed, since we can't store more - than one insn in an insn structure. */ - -static void -assemble_tokens_to_insn (const char *opname, - const expressionS *tok, - int ntok, - struct alpha_insn *insn) -{ - const struct alpha_opcode *opcode; - - /* Search opcodes. */ - opcode = (const struct alpha_opcode *) hash_find (alpha_opcode_hash, opname); - if (opcode) - { - int cpumatch; - opcode = find_opcode_match (opcode, tok, &ntok, &cpumatch); - if (opcode) - { - assemble_insn (opcode, tok, ntok, insn, BFD_RELOC_UNUSED); - return; - } - else if (cpumatch) - as_bad (_("inappropriate arguments for opcode `%s'"), opname); - else - as_bad (_("opcode `%s' not supported for target %s"), opname, - alpha_target_name); - } - else - as_bad (_("unknown opcode `%s'"), opname); -} - -/* Build a BFD section with its flags set appropriately for the .lita, - .lit8, or .lit4 sections. */ - -static void -create_literal_section (const char *name, - segT *secp, - symbolS **symp) -{ - segT current_section = now_seg; - int current_subsec = now_subseg; - segT new_sec; - - *secp = new_sec = subseg_new (name, 0); - subseg_set (current_section, current_subsec); - bfd_set_section_alignment (stdoutput, new_sec, 4); - bfd_set_section_flags (stdoutput, new_sec, - SEC_RELOC | SEC_ALLOC | SEC_LOAD | SEC_READONLY - | SEC_DATA); - - S_CLEAR_EXTERNAL (*symp = section_symbol (new_sec)); -} - -/* Load a (partial) expression into a target register. - - If poffset is not null, after the call it will either contain - O_constant 0, or a 16-bit offset appropriate for any MEM format - instruction. In addition, pbasereg will be modified to point to - the base register to use in that MEM format instruction. - - In any case, *pbasereg should contain a base register to add to the - expression. This will normally be either AXP_REG_ZERO or - alpha_gp_register. Symbol addresses will always be loaded via $gp, - so "foo($0)" is interpreted as adding the address of foo to $0; - i.e. "ldq $targ, LIT($gp); addq $targ, $0, $targ". Odd, perhaps, - but this is what OSF/1 does. - - If explicit relocations of the form !literal!<number> are allowed, - and used, then explicit_reloc with be an expression pointer. - - Finally, the return value is nonzero if the calling macro may emit - a LITUSE reloc if otherwise appropriate; the return value is the - sequence number to use. */ - -static long -load_expression (int targreg, - const expressionS *exp, - int *pbasereg, - expressionS *poffset, - const char *opname) -{ - long emit_lituse = 0; - offsetT addend = exp->X_add_number; - int basereg = *pbasereg; - struct alpha_insn insn; - expressionS newtok[3]; - - switch (exp->X_op) - { - case O_symbol: - { -#ifdef OBJ_ECOFF - offsetT lit; - - /* Attempt to reduce .lit load by splitting the offset from - its symbol when possible, but don't create a situation in - which we'd fail. */ - if (!range_signed_32 (addend) && - (alpha_noat_on || targreg == AXP_REG_AT)) - { - lit = add_to_literal_pool (exp->X_add_symbol, addend, - alpha_lita_section, 8); - addend = 0; - } - else - lit = add_to_literal_pool (exp->X_add_symbol, 0, - alpha_lita_section, 8); - - if (lit >= 0x8000) - as_fatal (_("overflow in literal (.lita) table")); - - /* Emit "ldq r, lit(gp)". */ - - if (basereg != alpha_gp_register && targreg == basereg) - { - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - if (targreg == AXP_REG_AT) - as_bad (_("macro requires $at while $at in use")); - - set_tok_reg (newtok[0], AXP_REG_AT); - } - else - set_tok_reg (newtok[0], targreg); - - set_tok_sym (newtok[1], alpha_lita_symbol, lit); - set_tok_preg (newtok[2], alpha_gp_register); - - assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - - gas_assert (insn.nfixups == 1); - insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL; - insn.sequence = emit_lituse = next_sequence_num--; -#endif /* OBJ_ECOFF */ -#ifdef OBJ_ELF - /* Emit "ldq r, gotoff(gp)". */ - - if (basereg != alpha_gp_register && targreg == basereg) - { - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - if (targreg == AXP_REG_AT) - as_bad (_("macro requires $at while $at in use")); - - set_tok_reg (newtok[0], AXP_REG_AT); - } - else - set_tok_reg (newtok[0], targreg); - - /* XXX: Disable this .got minimizing optimization so that we can get - better instruction offset knowledge in the compiler. This happens - very infrequently anyway. */ - if (1 - || (!range_signed_32 (addend) - && (alpha_noat_on || targreg == AXP_REG_AT))) - { - newtok[1] = *exp; - addend = 0; - } - else - set_tok_sym (newtok[1], exp->X_add_symbol, 0); - - set_tok_preg (newtok[2], alpha_gp_register); - - assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - - gas_assert (insn.nfixups == 1); - insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL; - insn.sequence = emit_lituse = next_sequence_num--; -#endif /* OBJ_ELF */ -#ifdef OBJ_EVAX - /* Find symbol or symbol pointer in link section. */ - - if (exp->X_add_symbol == alpha_evax_proc->symbol) - { - /* Linkage-relative expression. */ - set_tok_reg (newtok[0], targreg); - - if (range_signed_16 (addend)) - { - set_tok_const (newtok[1], addend); - addend = 0; - } - else - { - set_tok_const (newtok[1], 0); - } - set_tok_preg (newtok[2], basereg); - assemble_tokens_to_insn ("lda", newtok, 3, &insn); - } - else - { - const char *symname = S_GET_NAME (exp->X_add_symbol); - const char *ptr1, *ptr2; - int symlen = strlen (symname); - - if ((symlen > 4 && - strcmp (ptr2 = &symname [symlen - 4], "..lk") == 0)) - { - /* Access to an item whose address is stored in the linkage - section. Just read the address. */ - set_tok_reg (newtok[0], targreg); - - newtok[1] = *exp; - newtok[1].X_op = O_subtract; - newtok[1].X_op_symbol = alpha_evax_proc->symbol; - - set_tok_preg (newtok[2], basereg); - assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - alpha_linkage_symbol = exp->X_add_symbol; - - if (poffset) - set_tok_const (*poffset, 0); - - if (alpha_flag_replace && targreg == 26) - { - /* Add a NOP fixup for 'ldX $26,YYY..NAME..lk'. */ - char *ensymname; - symbolS *ensym; - - /* Build the entry name as 'NAME..en'. */ - ptr1 = strstr (symname, "..") + 2; - if (ptr1 > ptr2) - ptr1 = symname; - ensymname = (char *) alloca (ptr2 - ptr1 + 5); - memcpy (ensymname, ptr1, ptr2 - ptr1); - memcpy (ensymname + (ptr2 - ptr1), "..en", 5); - - gas_assert (insn.nfixups + 1 <= MAX_INSN_FIXUPS); - insn.fixups[insn.nfixups].reloc = BFD_RELOC_ALPHA_NOP; - ensym = symbol_find_or_make (ensymname); - symbol_mark_used (ensym); - /* The fixup must be the same as the BFD_RELOC_ALPHA_BOH - case in emit_jsrjmp. See B.4.5.2 of the OpenVMS Linker - Utility Manual. */ - insn.fixups[insn.nfixups].exp.X_op = O_symbol; - insn.fixups[insn.nfixups].exp.X_add_symbol = ensym; - insn.fixups[insn.nfixups].exp.X_add_number = 0; - insn.fixups[insn.nfixups].xtrasym = alpha_linkage_symbol; - insn.fixups[insn.nfixups].procsym = alpha_evax_proc->symbol; - insn.nfixups++; - - /* ??? Force bsym to be instantiated now, as it will be - too late to do so in tc_gen_reloc. */ - symbol_get_bfdsym (exp->X_add_symbol); - } - else if (alpha_flag_replace && targreg == 27) - { - /* Add a lda fixup for 'ldX $27,YYY.NAME..lk+8'. */ - char *psymname; - symbolS *psym; - - /* Extract NAME. */ - ptr1 = strstr (symname, "..") + 2; - if (ptr1 > ptr2) - ptr1 = symname; - psymname = (char *) alloca (ptr2 - ptr1 + 1); - memcpy (psymname, ptr1, ptr2 - ptr1); - psymname [ptr2 - ptr1] = 0; - - gas_assert (insn.nfixups + 1 <= MAX_INSN_FIXUPS); - insn.fixups[insn.nfixups].reloc = BFD_RELOC_ALPHA_LDA; - psym = symbol_find_or_make (psymname); - symbol_mark_used (psym); - insn.fixups[insn.nfixups].exp.X_op = O_subtract; - insn.fixups[insn.nfixups].exp.X_add_symbol = psym; - insn.fixups[insn.nfixups].exp.X_op_symbol = alpha_evax_proc->symbol; - insn.fixups[insn.nfixups].exp.X_add_number = 0; - insn.fixups[insn.nfixups].xtrasym = alpha_linkage_symbol; - insn.fixups[insn.nfixups].procsym = alpha_evax_proc->symbol; - insn.nfixups++; - } - - emit_insn (&insn); - return 0; - } - else - { - /* Not in the linkage section. Put the value into the linkage - section. */ - symbolS *linkexp; - - if (!range_signed_32 (addend)) - addend = sign_extend_32 (addend); - linkexp = add_to_link_pool (exp->X_add_symbol, 0); - set_tok_reg (newtok[0], targreg); - set_tok_sym (newtok[1], linkexp, 0); - set_tok_preg (newtok[2], basereg); - assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - } - } -#endif /* OBJ_EVAX */ - - emit_insn (&insn); - -#ifndef OBJ_EVAX - if (basereg != alpha_gp_register && basereg != AXP_REG_ZERO) - { - /* Emit "addq r, base, r". */ - - set_tok_reg (newtok[1], basereg); - set_tok_reg (newtok[2], targreg); - assemble_tokens ("addq", newtok, 3, 0); - } -#endif - basereg = targreg; - } - break; - - case O_constant: - break; - - case O_subtract: - /* Assume that this difference expression will be resolved to an - absolute value and that that value will fit in 16 bits. */ - - set_tok_reg (newtok[0], targreg); - newtok[1] = *exp; - set_tok_preg (newtok[2], basereg); - assemble_tokens (opname, newtok, 3, 0); - - if (poffset) - set_tok_const (*poffset, 0); - return 0; - - case O_big: - if (exp->X_add_number > 0) - as_bad (_("bignum invalid; zero assumed")); - else - as_bad (_("floating point number invalid; zero assumed")); - addend = 0; - break; - - default: - as_bad (_("can't handle expression")); - addend = 0; - break; - } - - if (!range_signed_32 (addend)) - { -#ifdef OBJ_EVAX - symbolS *litexp; -#else - offsetT lit; - long seq_num = next_sequence_num--; -#endif - - /* For 64-bit addends, just put it in the literal pool. */ -#ifdef OBJ_EVAX - /* Emit "ldq targreg, lit(basereg)". */ - litexp = add_to_link_pool (section_symbol (absolute_section), addend); - set_tok_reg (newtok[0], targreg); - set_tok_sym (newtok[1], litexp, 0); - set_tok_preg (newtok[2], alpha_gp_register); - assemble_tokens ("ldq", newtok, 3, 0); -#else - - if (alpha_lit8_section == NULL) - { - create_literal_section (".lit8", - &alpha_lit8_section, - &alpha_lit8_symbol); - -#ifdef OBJ_ECOFF - alpha_lit8_literal = add_to_literal_pool (alpha_lit8_symbol, 0x8000, - alpha_lita_section, 8); - if (alpha_lit8_literal >= 0x8000) - as_fatal (_("overflow in literal (.lita) table")); -#endif - } - - lit = add_to_literal_pool (NULL, addend, alpha_lit8_section, 8) - 0x8000; - if (lit >= 0x8000) - as_fatal (_("overflow in literal (.lit8) table")); - - /* Emit "lda litreg, .lit8+0x8000". */ - - if (targreg == basereg) - { - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - if (targreg == AXP_REG_AT) - as_bad (_("macro requires $at while $at in use")); - - set_tok_reg (newtok[0], AXP_REG_AT); - } - else - set_tok_reg (newtok[0], targreg); -#ifdef OBJ_ECOFF - set_tok_sym (newtok[1], alpha_lita_symbol, alpha_lit8_literal); -#endif -#ifdef OBJ_ELF - set_tok_sym (newtok[1], alpha_lit8_symbol, 0x8000); -#endif - set_tok_preg (newtok[2], alpha_gp_register); - - assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - - gas_assert (insn.nfixups == 1); -#ifdef OBJ_ECOFF - insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL; -#endif -#ifdef OBJ_ELF - insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL; -#endif - insn.sequence = seq_num; - - emit_insn (&insn); - - /* Emit "ldq litreg, lit(litreg)". */ - - set_tok_const (newtok[1], lit); - set_tok_preg (newtok[2], newtok[0].X_add_number); - - assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - - gas_assert (insn.nfixups < MAX_INSN_FIXUPS); - insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE; - insn.fixups[insn.nfixups].exp.X_op = O_absent; - insn.nfixups++; - insn.sequence = seq_num; - emit_lituse = 0; - - emit_insn (&insn); - - /* Emit "addq litreg, base, target". */ - - if (basereg != AXP_REG_ZERO) - { - set_tok_reg (newtok[1], basereg); - set_tok_reg (newtok[2], targreg); - assemble_tokens ("addq", newtok, 3, 0); - } -#endif /* !OBJ_EVAX */ - - if (poffset) - set_tok_const (*poffset, 0); - *pbasereg = targreg; - } - else - { - offsetT low, high, extra, tmp; - - /* For 32-bit operands, break up the addend. */ - - low = sign_extend_16 (addend); - tmp = addend - low; - high = sign_extend_16 (tmp >> 16); - - if (tmp - (high << 16)) - { - extra = 0x4000; - tmp -= 0x40000000; - high = sign_extend_16 (tmp >> 16); - } - else - extra = 0; - - set_tok_reg (newtok[0], targreg); - set_tok_preg (newtok[2], basereg); - - if (extra) - { - /* Emit "ldah r, extra(r). */ - set_tok_const (newtok[1], extra); - assemble_tokens ("ldah", newtok, 3, 0); - set_tok_preg (newtok[2], basereg = targreg); - } - - if (high) - { - /* Emit "ldah r, high(r). */ - set_tok_const (newtok[1], high); - assemble_tokens ("ldah", newtok, 3, 0); - basereg = targreg; - set_tok_preg (newtok[2], basereg); - } - - if ((low && !poffset) || (!poffset && basereg != targreg)) - { - /* Emit "lda r, low(base)". */ - set_tok_const (newtok[1], low); - assemble_tokens ("lda", newtok, 3, 0); - basereg = targreg; - low = 0; - } - - if (poffset) - set_tok_const (*poffset, low); - *pbasereg = basereg; - } - - return emit_lituse; -} - -/* The lda macro differs from the lda instruction in that it handles - most simple expressions, particularly symbol address loads and - large constants. */ - -static void -emit_lda (const expressionS *tok, - int ntok, - const void * unused ATTRIBUTE_UNUSED) -{ - int basereg; - - if (ntok == 2) - basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register); - else - basereg = tok[2].X_add_number; - - (void) load_expression (tok[0].X_add_number, &tok[1], &basereg, NULL, "lda"); -} - -/* The ldah macro differs from the ldah instruction in that it has $31 - as an implied base register. */ - -static void -emit_ldah (const expressionS *tok, - int ntok ATTRIBUTE_UNUSED, - const void * unused ATTRIBUTE_UNUSED) -{ - expressionS newtok[3]; - - newtok[0] = tok[0]; - newtok[1] = tok[1]; - set_tok_preg (newtok[2], AXP_REG_ZERO); - - assemble_tokens ("ldah", newtok, 3, 0); -} - -/* Called internally to handle all alignment needs. This takes care - of eliding calls to frag_align if'n the cached current alignment - says we've already got it, as well as taking care of the auto-align - feature wrt labels. */ - -static void -alpha_align (int n, - char *pfill, - symbolS *label, - int force ATTRIBUTE_UNUSED) -{ - if (alpha_current_align >= n) - return; - - if (pfill == NULL) - { - if (subseg_text_p (now_seg)) - frag_align_code (n, 0); - else - frag_align (n, 0, 0); - } - else - frag_align (n, *pfill, 0); - - alpha_current_align = n; - - if (label != NULL && S_GET_SEGMENT (label) == now_seg) - { - symbol_set_frag (label, frag_now); - S_SET_VALUE (label, (valueT) frag_now_fix ()); - } - - record_alignment (now_seg, n); - - /* ??? If alpha_flag_relax && force && elf, record the requested alignment - in a reloc for the linker to see. */ -} - -/* Actually output an instruction with its fixup. */ - -static void -emit_insn (struct alpha_insn *insn) -{ - char *f; - int i; - - /* Take care of alignment duties. */ - if (alpha_auto_align_on && alpha_current_align < 2) - alpha_align (2, (char *) NULL, alpha_insn_label, 0); - if (alpha_current_align > 2) - alpha_current_align = 2; - alpha_insn_label = NULL; - - /* Write out the instruction. */ - f = frag_more (4); - md_number_to_chars (f, insn->insn, 4); - -#ifdef OBJ_ELF - dwarf2_emit_insn (4); -#endif - - /* Apply the fixups in order. */ - for (i = 0; i < insn->nfixups; ++i) - { - const struct alpha_operand *operand = (const struct alpha_operand *) 0; - struct alpha_fixup *fixup = &insn->fixups[i]; - struct alpha_reloc_tag *info = NULL; - int size, pcrel; - fixS *fixP; - - /* Some fixups are only used internally and so have no howto. */ - if ((int) fixup->reloc < 0) - { - operand = &alpha_operands[-(int) fixup->reloc]; - size = 4; - pcrel = ((operand->flags & AXP_OPERAND_RELATIVE) != 0); - } - else if (fixup->reloc > BFD_RELOC_UNUSED - || fixup->reloc == BFD_RELOC_ALPHA_GPDISP_HI16 - || fixup->reloc == BFD_RELOC_ALPHA_GPDISP_LO16) - { - size = 2; - pcrel = 0; - } - else - { - reloc_howto_type *reloc_howto = - bfd_reloc_type_lookup (stdoutput, - (bfd_reloc_code_real_type) fixup->reloc); - gas_assert (reloc_howto); - - size = bfd_get_reloc_size (reloc_howto); - - switch (fixup->reloc) - { -#ifdef OBJ_EVAX - case BFD_RELOC_ALPHA_NOP: - case BFD_RELOC_ALPHA_BSR: - case BFD_RELOC_ALPHA_LDA: - case BFD_RELOC_ALPHA_BOH: - break; -#endif - default: - gas_assert (size >= 1 && size <= 4); - } - - pcrel = reloc_howto->pc_relative; - } - - fixP = fix_new_exp (frag_now, f - frag_now->fr_literal, size, - &fixup->exp, pcrel, (bfd_reloc_code_real_type) fixup->reloc); - - /* Turn off complaints that the addend is too large for some fixups, - and copy in the sequence number for the explicit relocations. */ - switch (fixup->reloc) - { - case BFD_RELOC_ALPHA_HINT: - case BFD_RELOC_GPREL32: - case BFD_RELOC_GPREL16: - case BFD_RELOC_ALPHA_GPREL_HI16: - case BFD_RELOC_ALPHA_GPREL_LO16: - case BFD_RELOC_ALPHA_GOTDTPREL16: - case BFD_RELOC_ALPHA_DTPREL_HI16: - case BFD_RELOC_ALPHA_DTPREL_LO16: - case BFD_RELOC_ALPHA_DTPREL16: - case BFD_RELOC_ALPHA_GOTTPREL16: - case BFD_RELOC_ALPHA_TPREL_HI16: - case BFD_RELOC_ALPHA_TPREL_LO16: - case BFD_RELOC_ALPHA_TPREL16: - fixP->fx_no_overflow = 1; - break; - - case BFD_RELOC_ALPHA_GPDISP_HI16: - fixP->fx_no_overflow = 1; - fixP->fx_addsy = section_symbol (now_seg); - fixP->fx_offset = 0; - - info = get_alpha_reloc_tag (insn->sequence); - if (++info->n_master > 1) - as_bad (_("too many ldah insns for !gpdisp!%ld"), insn->sequence); - if (info->segment != now_seg) - as_bad (_("both insns for !gpdisp!%ld must be in the same section"), - insn->sequence); - fixP->tc_fix_data.info = info; - break; - - case BFD_RELOC_ALPHA_GPDISP_LO16: - fixP->fx_no_overflow = 1; - - info = get_alpha_reloc_tag (insn->sequence); - if (++info->n_slaves > 1) - as_bad (_("too many lda insns for !gpdisp!%ld"), insn->sequence); - if (info->segment != now_seg) - as_bad (_("both insns for !gpdisp!%ld must be in the same section"), - insn->sequence); - fixP->tc_fix_data.info = info; - info->slaves = fixP; - break; - - case BFD_RELOC_ALPHA_LITERAL: - case BFD_RELOC_ALPHA_ELF_LITERAL: - fixP->fx_no_overflow = 1; - - if (insn->sequence == 0) - break; - info = get_alpha_reloc_tag (insn->sequence); - info->master = fixP; - info->n_master++; - if (info->segment != now_seg) - info->multi_section_p = 1; - fixP->tc_fix_data.info = info; - break; - -#ifdef RELOC_OP_P - case DUMMY_RELOC_LITUSE_ADDR: - fixP->fx_offset = LITUSE_ALPHA_ADDR; - goto do_lituse; - case DUMMY_RELOC_LITUSE_BASE: - fixP->fx_offset = LITUSE_ALPHA_BASE; - goto do_lituse; - case DUMMY_RELOC_LITUSE_BYTOFF: - fixP->fx_offset = LITUSE_ALPHA_BYTOFF; - goto do_lituse; - case DUMMY_RELOC_LITUSE_JSR: - fixP->fx_offset = LITUSE_ALPHA_JSR; - goto do_lituse; - case DUMMY_RELOC_LITUSE_TLSGD: - fixP->fx_offset = LITUSE_ALPHA_TLSGD; - goto do_lituse; - case DUMMY_RELOC_LITUSE_TLSLDM: - fixP->fx_offset = LITUSE_ALPHA_TLSLDM; - goto do_lituse; - case DUMMY_RELOC_LITUSE_JSRDIRECT: - fixP->fx_offset = LITUSE_ALPHA_JSRDIRECT; - goto do_lituse; - do_lituse: - fixP->fx_addsy = section_symbol (now_seg); - fixP->fx_r_type = BFD_RELOC_ALPHA_LITUSE; - - info = get_alpha_reloc_tag (insn->sequence); - if (fixup->reloc == DUMMY_RELOC_LITUSE_TLSGD) - info->saw_lu_tlsgd = 1; - else if (fixup->reloc == DUMMY_RELOC_LITUSE_TLSLDM) - info->saw_lu_tlsldm = 1; - if (++info->n_slaves > 1) - { - if (info->saw_lu_tlsgd) - as_bad (_("too many lituse insns for !lituse_tlsgd!%ld"), - insn->sequence); - else if (info->saw_lu_tlsldm) - as_bad (_("too many lituse insns for !lituse_tlsldm!%ld"), - insn->sequence); - } - fixP->tc_fix_data.info = info; - fixP->tc_fix_data.next_reloc = info->slaves; - info->slaves = fixP; - if (info->segment != now_seg) - info->multi_section_p = 1; - break; - - case BFD_RELOC_ALPHA_TLSGD: - fixP->fx_no_overflow = 1; - - if (insn->sequence == 0) - break; - info = get_alpha_reloc_tag (insn->sequence); - if (info->saw_tlsgd) - as_bad (_("duplicate !tlsgd!%ld"), insn->sequence); - else if (info->saw_tlsldm) - as_bad (_("sequence number in use for !tlsldm!%ld"), - insn->sequence); - else - info->saw_tlsgd = 1; - fixP->tc_fix_data.info = info; - break; - - case BFD_RELOC_ALPHA_TLSLDM: - fixP->fx_no_overflow = 1; - - if (insn->sequence == 0) - break; - info = get_alpha_reloc_tag (insn->sequence); - if (info->saw_tlsldm) - as_bad (_("duplicate !tlsldm!%ld"), insn->sequence); - else if (info->saw_tlsgd) - as_bad (_("sequence number in use for !tlsgd!%ld"), - insn->sequence); - else - info->saw_tlsldm = 1; - fixP->tc_fix_data.info = info; - break; -#endif -#ifdef OBJ_EVAX - case BFD_RELOC_ALPHA_NOP: - case BFD_RELOC_ALPHA_LDA: - case BFD_RELOC_ALPHA_BSR: - case BFD_RELOC_ALPHA_BOH: - info = get_alpha_reloc_tag (next_sequence_num--); - fixP->tc_fix_data.info = info; - fixP->tc_fix_data.info->sym = fixup->xtrasym; - fixP->tc_fix_data.info->psym = fixup->procsym; - break; -#endif - - default: - if ((int) fixup->reloc < 0) - { - if (operand->flags & AXP_OPERAND_NOOVERFLOW) - fixP->fx_no_overflow = 1; - } - break; - } - } -} - -/* Insert an operand value into an instruction. */ - -static unsigned -insert_operand (unsigned insn, - const struct alpha_operand *operand, - offsetT val, - char *file, - unsigned line) -{ - if (operand->bits != 32 && !(operand->flags & AXP_OPERAND_NOOVERFLOW)) - { - offsetT min, max; - - if (operand->flags & AXP_OPERAND_SIGNED) - { - max = (1 << (operand->bits - 1)) - 1; - min = -(1 << (operand->bits - 1)); - } - else - { - max = (1 << operand->bits) - 1; - min = 0; - } - - if (val < min || val > max) - as_bad_value_out_of_range (_("operand"), val, min, max, file, line); - } - - if (operand->insert) - { - const char *errmsg = NULL; - - insn = (*operand->insert) (insn, val, &errmsg); - if (errmsg) - as_warn ("%s", errmsg); - } - else - insn |= ((val & ((1 << operand->bits) - 1)) << operand->shift); - - return insn; -} - -/* Turn an opcode description and a set of arguments into - an instruction and a fixup. */ - -static void -assemble_insn (const struct alpha_opcode *opcode, - const expressionS *tok, - int ntok, - struct alpha_insn *insn, - extended_bfd_reloc_code_real_type reloc) -{ - const struct alpha_operand *reloc_operand = NULL; - const expressionS *reloc_exp = NULL; - const unsigned char *argidx; - unsigned image; - int tokidx = 0; - - memset (insn, 0, sizeof (*insn)); - image = opcode->opcode; - - for (argidx = opcode->operands; *argidx; ++argidx) - { - const struct alpha_operand *operand = &alpha_operands[*argidx]; - const expressionS *t = (const expressionS *) 0; - - if (operand->flags & AXP_OPERAND_FAKE) - { - /* Fake operands take no value and generate no fixup. */ - image = insert_operand (image, operand, 0, NULL, 0); - continue; - } - - if (tokidx >= ntok) - { - switch (operand->flags & AXP_OPERAND_OPTIONAL_MASK) - { - case AXP_OPERAND_DEFAULT_FIRST: - t = &tok[0]; - break; - case AXP_OPERAND_DEFAULT_SECOND: - t = &tok[1]; - break; - case AXP_OPERAND_DEFAULT_ZERO: - { - static expressionS zero_exp; - t = &zero_exp; - zero_exp.X_op = O_constant; - zero_exp.X_unsigned = 1; - } - break; - default: - abort (); - } - } - else - t = &tok[tokidx++]; - - switch (t->X_op) - { - case O_register: - case O_pregister: - case O_cpregister: - image = insert_operand (image, operand, regno (t->X_add_number), - NULL, 0); - break; - - case O_constant: - image = insert_operand (image, operand, t->X_add_number, NULL, 0); - gas_assert (reloc_operand == NULL); - reloc_operand = operand; - reloc_exp = t; - break; - - default: - /* This is only 0 for fields that should contain registers, - which means this pattern shouldn't have matched. */ - if (operand->default_reloc == 0) - abort (); - - /* There is one special case for which an insn receives two - relocations, and thus the user-supplied reloc does not - override the operand reloc. */ - if (operand->default_reloc == BFD_RELOC_ALPHA_HINT) - { - struct alpha_fixup *fixup; - - if (insn->nfixups >= MAX_INSN_FIXUPS) - as_fatal (_("too many fixups")); - - fixup = &insn->fixups[insn->nfixups++]; - fixup->exp = *t; - fixup->reloc = BFD_RELOC_ALPHA_HINT; - } - else - { - if (reloc == BFD_RELOC_UNUSED) - reloc = operand->default_reloc; - - gas_assert (reloc_operand == NULL); - reloc_operand = operand; - reloc_exp = t; - } - break; - } - } - - if (reloc != BFD_RELOC_UNUSED) - { - struct alpha_fixup *fixup; - - if (insn->nfixups >= MAX_INSN_FIXUPS) - as_fatal (_("too many fixups")); - - /* ??? My but this is hacky. But the OSF/1 assembler uses the same - relocation tag for both ldah and lda with gpdisp. Choose the - correct internal relocation based on the opcode. */ - if (reloc == BFD_RELOC_ALPHA_GPDISP) - { - if (strcmp (opcode->name, "ldah") == 0) - reloc = BFD_RELOC_ALPHA_GPDISP_HI16; - else if (strcmp (opcode->name, "lda") == 0) - reloc = BFD_RELOC_ALPHA_GPDISP_LO16; - else - as_bad (_("invalid relocation for instruction")); - } - - /* If this is a real relocation (as opposed to a lituse hint), then - the relocation width should match the operand width. - Take care of -MDISP in operand table. */ - else if (reloc < BFD_RELOC_UNUSED && reloc > 0) - { - reloc_howto_type *reloc_howto - = bfd_reloc_type_lookup (stdoutput, - (bfd_reloc_code_real_type) reloc); - if (reloc_operand == NULL - || reloc_howto->bitsize != reloc_operand->bits) - { - as_bad (_("invalid relocation for field")); - return; - } - } - - fixup = &insn->fixups[insn->nfixups++]; - if (reloc_exp) - fixup->exp = *reloc_exp; - else - fixup->exp.X_op = O_absent; - fixup->reloc = reloc; - } - - insn->insn = image; -} - -/* Handle all "simple" integer register loads -- ldq, ldq_l, ldq_u, - etc. They differ from the real instructions in that they do simple - expressions like the lda macro. */ - -static void -emit_ir_load (const expressionS *tok, - int ntok, - const void * opname) -{ - int basereg; - long lituse; - expressionS newtok[3]; - struct alpha_insn insn; - const char *symname - = tok[1].X_add_symbol ? S_GET_NAME (tok[1].X_add_symbol): ""; - int symlen = strlen (symname); - - if (ntok == 2) - basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register); - else - basereg = tok[2].X_add_number; - - lituse = load_expression (tok[0].X_add_number, &tok[1], - &basereg, &newtok[1], (const char *) opname); - - if (basereg == alpha_gp_register && - (symlen > 4 && strcmp (&symname [symlen - 4], "..lk") == 0)) - return; - - newtok[0] = tok[0]; - set_tok_preg (newtok[2], basereg); - - assemble_tokens_to_insn ((const char *) opname, newtok, 3, &insn); - - if (lituse) - { - gas_assert (insn.nfixups < MAX_INSN_FIXUPS); - insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE; - insn.fixups[insn.nfixups].exp.X_op = O_absent; - insn.nfixups++; - insn.sequence = lituse; - } - - emit_insn (&insn); -} - -/* Handle fp register loads, and both integer and fp register stores. - Again, we handle simple expressions. */ - -static void -emit_loadstore (const expressionS *tok, - int ntok, - const void * opname) -{ - int basereg; - long lituse; - expressionS newtok[3]; - struct alpha_insn insn; - - if (ntok == 2) - basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register); - else - basereg = tok[2].X_add_number; - - if (tok[1].X_op != O_constant || !range_signed_16 (tok[1].X_add_number)) - { - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - - lituse = load_expression (AXP_REG_AT, &tok[1], - &basereg, &newtok[1], (const char *) opname); - } - else - { - newtok[1] = tok[1]; - lituse = 0; - } - - newtok[0] = tok[0]; - set_tok_preg (newtok[2], basereg); - - assemble_tokens_to_insn ((const char *) opname, newtok, 3, &insn); - - if (lituse) - { - gas_assert (insn.nfixups < MAX_INSN_FIXUPS); - insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE; - insn.fixups[insn.nfixups].exp.X_op = O_absent; - insn.nfixups++; - insn.sequence = lituse; - } - - emit_insn (&insn); -} - -/* Load a half-word or byte as an unsigned value. */ - -static void -emit_ldXu (const expressionS *tok, - int ntok, - const void * vlgsize) -{ - if (alpha_target & AXP_OPCODE_BWX) - emit_ir_load (tok, ntok, ldXu_op[(long) vlgsize]); - else - { - expressionS newtok[3]; - struct alpha_insn insn; - int basereg; - long lituse; - - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - - if (ntok == 2) - basereg = (tok[1].X_op == O_constant - ? AXP_REG_ZERO : alpha_gp_register); - else - basereg = tok[2].X_add_number; - - /* Emit "lda $at, exp". */ - lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL, "lda"); - - /* Emit "ldq_u targ, 0($at)". */ - newtok[0] = tok[0]; - set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], basereg); - assemble_tokens_to_insn ("ldq_u", newtok, 3, &insn); - - if (lituse) - { - gas_assert (insn.nfixups < MAX_INSN_FIXUPS); - insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE; - insn.fixups[insn.nfixups].exp.X_op = O_absent; - insn.nfixups++; - insn.sequence = lituse; - } - - emit_insn (&insn); - - /* Emit "extXl targ, $at, targ". */ - set_tok_reg (newtok[1], basereg); - newtok[2] = newtok[0]; - assemble_tokens_to_insn (extXl_op[(long) vlgsize], newtok, 3, &insn); - - if (lituse) - { - gas_assert (insn.nfixups < MAX_INSN_FIXUPS); - insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BYTOFF; - insn.fixups[insn.nfixups].exp.X_op = O_absent; - insn.nfixups++; - insn.sequence = lituse; - } - - emit_insn (&insn); - } -} - -/* Load a half-word or byte as a signed value. */ - -static void -emit_ldX (const expressionS *tok, - int ntok, - const void * vlgsize) -{ - emit_ldXu (tok, ntok, vlgsize); - assemble_tokens (sextX_op[(long) vlgsize], tok, 1, 1); -} - -/* Load an integral value from an unaligned address as an unsigned - value. */ - -static void -emit_uldXu (const expressionS *tok, - int ntok, - const void * vlgsize) -{ - long lgsize = (long) vlgsize; - expressionS newtok[3]; - - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - - /* Emit "lda $at, exp". */ - memcpy (newtok, tok, sizeof (expressionS) * ntok); - newtok[0].X_add_number = AXP_REG_AT; - assemble_tokens ("lda", newtok, ntok, 1); - - /* Emit "ldq_u $t9, 0($at)". */ - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], AXP_REG_AT); - assemble_tokens ("ldq_u", newtok, 3, 1); - - /* Emit "ldq_u $t10, size-1($at)". */ - set_tok_reg (newtok[0], AXP_REG_T10); - set_tok_const (newtok[1], (1 << lgsize) - 1); - assemble_tokens ("ldq_u", newtok, 3, 1); - - /* Emit "extXl $t9, $at, $t9". */ - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_reg (newtok[1], AXP_REG_AT); - set_tok_reg (newtok[2], AXP_REG_T9); - assemble_tokens (extXl_op[lgsize], newtok, 3, 1); - - /* Emit "extXh $t10, $at, $t10". */ - set_tok_reg (newtok[0], AXP_REG_T10); - set_tok_reg (newtok[2], AXP_REG_T10); - assemble_tokens (extXh_op[lgsize], newtok, 3, 1); - - /* Emit "or $t9, $t10, targ". */ - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_reg (newtok[1], AXP_REG_T10); - newtok[2] = tok[0]; - assemble_tokens ("or", newtok, 3, 1); -} - -/* Load an integral value from an unaligned address as a signed value. - Note that quads should get funneled to the unsigned load since we - don't have to do the sign extension. */ - -static void -emit_uldX (const expressionS *tok, - int ntok, - const void * vlgsize) -{ - emit_uldXu (tok, ntok, vlgsize); - assemble_tokens (sextX_op[(long) vlgsize], tok, 1, 1); -} - -/* Implement the ldil macro. */ - -static void -emit_ldil (const expressionS *tok, - int ntok, - const void * unused ATTRIBUTE_UNUSED) -{ - expressionS newtok[2]; - - memcpy (newtok, tok, sizeof (newtok)); - newtok[1].X_add_number = sign_extend_32 (tok[1].X_add_number); - - assemble_tokens ("lda", newtok, ntok, 1); -} - -/* Store a half-word or byte. */ - -static void -emit_stX (const expressionS *tok, - int ntok, - const void * vlgsize) -{ - int lgsize = (int) (long) vlgsize; - - if (alpha_target & AXP_OPCODE_BWX) - emit_loadstore (tok, ntok, stX_op[lgsize]); - else - { - expressionS newtok[3]; - struct alpha_insn insn; - int basereg; - long lituse; - - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - - if (ntok == 2) - basereg = (tok[1].X_op == O_constant - ? AXP_REG_ZERO : alpha_gp_register); - else - basereg = tok[2].X_add_number; - - /* Emit "lda $at, exp". */ - lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL, "lda"); - - /* Emit "ldq_u $t9, 0($at)". */ - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], basereg); - assemble_tokens_to_insn ("ldq_u", newtok, 3, &insn); - - if (lituse) - { - gas_assert (insn.nfixups < MAX_INSN_FIXUPS); - insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE; - insn.fixups[insn.nfixups].exp.X_op = O_absent; - insn.nfixups++; - insn.sequence = lituse; - } - - emit_insn (&insn); - - /* Emit "insXl src, $at, $t10". */ - newtok[0] = tok[0]; - set_tok_reg (newtok[1], basereg); - set_tok_reg (newtok[2], AXP_REG_T10); - assemble_tokens_to_insn (insXl_op[lgsize], newtok, 3, &insn); - - if (lituse) - { - gas_assert (insn.nfixups < MAX_INSN_FIXUPS); - insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BYTOFF; - insn.fixups[insn.nfixups].exp.X_op = O_absent; - insn.nfixups++; - insn.sequence = lituse; - } - - emit_insn (&insn); - - /* Emit "mskXl $t9, $at, $t9". */ - set_tok_reg (newtok[0], AXP_REG_T9); - newtok[2] = newtok[0]; - assemble_tokens_to_insn (mskXl_op[lgsize], newtok, 3, &insn); - - if (lituse) - { - gas_assert (insn.nfixups < MAX_INSN_FIXUPS); - insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BYTOFF; - insn.fixups[insn.nfixups].exp.X_op = O_absent; - insn.nfixups++; - insn.sequence = lituse; - } - - emit_insn (&insn); - - /* Emit "or $t9, $t10, $t9". */ - set_tok_reg (newtok[1], AXP_REG_T10); - assemble_tokens ("or", newtok, 3, 1); - - /* Emit "stq_u $t9, 0($at). */ - set_tok_const(newtok[1], 0); - set_tok_preg (newtok[2], AXP_REG_AT); - assemble_tokens_to_insn ("stq_u", newtok, 3, &insn); - - if (lituse) - { - gas_assert (insn.nfixups < MAX_INSN_FIXUPS); - insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE; - insn.fixups[insn.nfixups].exp.X_op = O_absent; - insn.nfixups++; - insn.sequence = lituse; - } - - emit_insn (&insn); - } -} - -/* Store an integer to an unaligned address. */ - -static void -emit_ustX (const expressionS *tok, - int ntok, - const void * vlgsize) -{ - int lgsize = (int) (long) vlgsize; - expressionS newtok[3]; - - /* Emit "lda $at, exp". */ - memcpy (newtok, tok, sizeof (expressionS) * ntok); - newtok[0].X_add_number = AXP_REG_AT; - assemble_tokens ("lda", newtok, ntok, 1); - - /* Emit "ldq_u $9, 0($at)". */ - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], AXP_REG_AT); - assemble_tokens ("ldq_u", newtok, 3, 1); - - /* Emit "ldq_u $10, size-1($at)". */ - set_tok_reg (newtok[0], AXP_REG_T10); - set_tok_const (newtok[1], (1 << lgsize) - 1); - assemble_tokens ("ldq_u", newtok, 3, 1); - - /* Emit "insXl src, $at, $t11". */ - newtok[0] = tok[0]; - set_tok_reg (newtok[1], AXP_REG_AT); - set_tok_reg (newtok[2], AXP_REG_T11); - assemble_tokens (insXl_op[lgsize], newtok, 3, 1); - - /* Emit "insXh src, $at, $t12". */ - set_tok_reg (newtok[2], AXP_REG_T12); - assemble_tokens (insXh_op[lgsize], newtok, 3, 1); - - /* Emit "mskXl $t9, $at, $t9". */ - set_tok_reg (newtok[0], AXP_REG_T9); - newtok[2] = newtok[0]; - assemble_tokens (mskXl_op[lgsize], newtok, 3, 1); - - /* Emit "mskXh $t10, $at, $t10". */ - set_tok_reg (newtok[0], AXP_REG_T10); - newtok[2] = newtok[0]; - assemble_tokens (mskXh_op[lgsize], newtok, 3, 1); - - /* Emit "or $t9, $t11, $t9". */ - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_reg (newtok[1], AXP_REG_T11); - newtok[2] = newtok[0]; - assemble_tokens ("or", newtok, 3, 1); - - /* Emit "or $t10, $t12, $t10". */ - set_tok_reg (newtok[0], AXP_REG_T10); - set_tok_reg (newtok[1], AXP_REG_T12); - newtok[2] = newtok[0]; - assemble_tokens ("or", newtok, 3, 1); - - /* Emit "stq_u $t10, size-1($at)". */ - set_tok_reg (newtok[0], AXP_REG_T10); - set_tok_const (newtok[1], (1 << lgsize) - 1); - set_tok_preg (newtok[2], AXP_REG_AT); - assemble_tokens ("stq_u", newtok, 3, 1); - - /* Emit "stq_u $t9, 0($at)". */ - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_const (newtok[1], 0); - assemble_tokens ("stq_u", newtok, 3, 1); -} - -/* Sign extend a half-word or byte. The 32-bit sign extend is - implemented as "addl $31, $r, $t" in the opcode table. */ - -static void -emit_sextX (const expressionS *tok, - int ntok, - const void * vlgsize) -{ - long lgsize = (long) vlgsize; - - if (alpha_target & AXP_OPCODE_BWX) - assemble_tokens (sextX_op[lgsize], tok, ntok, 0); - else - { - int bitshift = 64 - 8 * (1 << lgsize); - expressionS newtok[3]; - - /* Emit "sll src,bits,dst". */ - newtok[0] = tok[0]; - set_tok_const (newtok[1], bitshift); - newtok[2] = tok[ntok - 1]; - assemble_tokens ("sll", newtok, 3, 1); - - /* Emit "sra dst,bits,dst". */ - newtok[0] = newtok[2]; - assemble_tokens ("sra", newtok, 3, 1); - } -} - -/* Implement the division and modulus macros. */ - -#ifdef OBJ_EVAX - -/* Make register usage like in normal procedure call. - Don't clobber PV and RA. */ - -static void -emit_division (const expressionS *tok, - int ntok, - const void * symname) -{ - /* DIVISION and MODULUS. Yech. - - Convert - OP x,y,result - to - mov x,R16 # if x != R16 - mov y,R17 # if y != R17 - lda AT,__OP - jsr AT,(AT),0 - mov R0,result - - with appropriate optimizations if R0,R16,R17 are the registers - specified by the compiler. */ - - int xr, yr, rr; - symbolS *sym; - expressionS newtok[3]; - - xr = regno (tok[0].X_add_number); - yr = regno (tok[1].X_add_number); - - if (ntok < 3) - rr = xr; - else - rr = regno (tok[2].X_add_number); - - /* Move the operands into the right place. */ - if (yr == AXP_REG_R16 && xr == AXP_REG_R17) - { - /* They are in exactly the wrong order -- swap through AT. */ - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - - set_tok_reg (newtok[0], AXP_REG_R16); - set_tok_reg (newtok[1], AXP_REG_AT); - assemble_tokens ("mov", newtok, 2, 1); - - set_tok_reg (newtok[0], AXP_REG_R17); - set_tok_reg (newtok[1], AXP_REG_R16); - assemble_tokens ("mov", newtok, 2, 1); - - set_tok_reg (newtok[0], AXP_REG_AT); - set_tok_reg (newtok[1], AXP_REG_R17); - assemble_tokens ("mov", newtok, 2, 1); - } - else - { - if (yr == AXP_REG_R16) - { - set_tok_reg (newtok[0], AXP_REG_R16); - set_tok_reg (newtok[1], AXP_REG_R17); - assemble_tokens ("mov", newtok, 2, 1); - } - - if (xr != AXP_REG_R16) - { - set_tok_reg (newtok[0], xr); - set_tok_reg (newtok[1], AXP_REG_R16); - assemble_tokens ("mov", newtok, 2, 1); - } - - if (yr != AXP_REG_R16 && yr != AXP_REG_R17) - { - set_tok_reg (newtok[0], yr); - set_tok_reg (newtok[1], AXP_REG_R17); - assemble_tokens ("mov", newtok, 2, 1); - } - } - - sym = symbol_find_or_make ((const char *) symname); - - set_tok_reg (newtok[0], AXP_REG_AT); - set_tok_sym (newtok[1], sym, 0); - assemble_tokens ("lda", newtok, 2, 1); - - /* Call the division routine. */ - set_tok_reg (newtok[0], AXP_REG_AT); - set_tok_cpreg (newtok[1], AXP_REG_AT); - set_tok_const (newtok[2], 0); - assemble_tokens ("jsr", newtok, 3, 1); - - /* Move the result to the right place. */ - if (rr != AXP_REG_R0) - { - set_tok_reg (newtok[0], AXP_REG_R0); - set_tok_reg (newtok[1], rr); - assemble_tokens ("mov", newtok, 2, 1); - } -} - -#else /* !OBJ_EVAX */ - -static void -emit_division (const expressionS *tok, - int ntok, - const void * symname) -{ - /* DIVISION and MODULUS. Yech. - Convert - OP x,y,result - to - lda pv,__OP - mov x,t10 - mov y,t11 - jsr t9,(pv),__OP - mov t12,result - - with appropriate optimizations if t10,t11,t12 are the registers - specified by the compiler. */ - - int xr, yr, rr; - symbolS *sym; - expressionS newtok[3]; - - xr = regno (tok[0].X_add_number); - yr = regno (tok[1].X_add_number); - - if (ntok < 3) - rr = xr; - else - rr = regno (tok[2].X_add_number); - - sym = symbol_find_or_make ((const char *) symname); - - /* Move the operands into the right place. */ - if (yr == AXP_REG_T10 && xr == AXP_REG_T11) - { - /* They are in exactly the wrong order -- swap through AT. */ - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - - set_tok_reg (newtok[0], AXP_REG_T10); - set_tok_reg (newtok[1], AXP_REG_AT); - assemble_tokens ("mov", newtok, 2, 1); - - set_tok_reg (newtok[0], AXP_REG_T11); - set_tok_reg (newtok[1], AXP_REG_T10); - assemble_tokens ("mov", newtok, 2, 1); - - set_tok_reg (newtok[0], AXP_REG_AT); - set_tok_reg (newtok[1], AXP_REG_T11); - assemble_tokens ("mov", newtok, 2, 1); - } - else - { - if (yr == AXP_REG_T10) - { - set_tok_reg (newtok[0], AXP_REG_T10); - set_tok_reg (newtok[1], AXP_REG_T11); - assemble_tokens ("mov", newtok, 2, 1); - } - - if (xr != AXP_REG_T10) - { - set_tok_reg (newtok[0], xr); - set_tok_reg (newtok[1], AXP_REG_T10); - assemble_tokens ("mov", newtok, 2, 1); - } - - if (yr != AXP_REG_T10 && yr != AXP_REG_T11) - { - set_tok_reg (newtok[0], yr); - set_tok_reg (newtok[1], AXP_REG_T11); - assemble_tokens ("mov", newtok, 2, 1); - } - } - - /* Call the division routine. */ - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_sym (newtok[1], sym, 0); - assemble_tokens ("jsr", newtok, 2, 1); - - /* Reload the GP register. */ -#ifdef OBJ_AOUT -FIXME -#endif -#if defined(OBJ_ECOFF) || defined(OBJ_ELF) - set_tok_reg (newtok[0], alpha_gp_register); - set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], AXP_REG_T9); - assemble_tokens ("ldgp", newtok, 3, 1); -#endif - - /* Move the result to the right place. */ - if (rr != AXP_REG_T12) - { - set_tok_reg (newtok[0], AXP_REG_T12); - set_tok_reg (newtok[1], rr); - assemble_tokens ("mov", newtok, 2, 1); - } -} - -#endif /* !OBJ_EVAX */ - -/* The jsr and jmp macros differ from their instruction counterparts - in that they can load the target address and default most - everything. */ - -static void -emit_jsrjmp (const expressionS *tok, - int ntok, - const void * vopname) -{ - const char *opname = (const char *) vopname; - struct alpha_insn insn; - expressionS newtok[3]; - int r, tokidx = 0; - long lituse = 0; - - if (tokidx < ntok && tok[tokidx].X_op == O_register) - r = regno (tok[tokidx++].X_add_number); - else - r = strcmp (opname, "jmp") == 0 ? AXP_REG_ZERO : AXP_REG_RA; - - set_tok_reg (newtok[0], r); - - if (tokidx < ntok && - (tok[tokidx].X_op == O_pregister || tok[tokidx].X_op == O_cpregister)) - r = regno (tok[tokidx++].X_add_number); -#ifdef OBJ_EVAX - /* Keep register if jsr $n.<sym>. */ -#else - else - { - int basereg = alpha_gp_register; - lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], - &basereg, NULL, opname); - } -#endif - - set_tok_cpreg (newtok[1], r); - -#ifndef OBJ_EVAX - if (tokidx < ntok) - newtok[2] = tok[tokidx]; - else -#endif - set_tok_const (newtok[2], 0); - - assemble_tokens_to_insn (opname, newtok, 3, &insn); - - if (lituse) - { - gas_assert (insn.nfixups < MAX_INSN_FIXUPS); - insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_JSR; - insn.fixups[insn.nfixups].exp.X_op = O_absent; - insn.nfixups++; - insn.sequence = lituse; - } - -#ifdef OBJ_EVAX - if (alpha_flag_replace - && r == AXP_REG_RA - && tok[tokidx].X_add_symbol - && alpha_linkage_symbol) - { - /* Create a BOH reloc for 'jsr $27,NAME'. */ - const char *symname = S_GET_NAME (tok[tokidx].X_add_symbol); - int symlen = strlen (symname); - char *ensymname; - - /* Build the entry name as 'NAME..en'. */ - ensymname = (char *) alloca (symlen + 5); - memcpy (ensymname, symname, symlen); - memcpy (ensymname + symlen, "..en", 5); - - gas_assert (insn.nfixups < MAX_INSN_FIXUPS); - if (insn.nfixups > 0) - { - memmove (&insn.fixups[1], &insn.fixups[0], - sizeof(struct alpha_fixup) * insn.nfixups); - } - - /* The fixup must be the same as the BFD_RELOC_ALPHA_NOP - case in load_expression. See B.4.5.2 of the OpenVMS - Linker Utility Manual. */ - insn.fixups[0].reloc = BFD_RELOC_ALPHA_BOH; - insn.fixups[0].exp.X_op = O_symbol; - insn.fixups[0].exp.X_add_symbol = symbol_find_or_make (ensymname); - insn.fixups[0].exp.X_add_number = 0; - insn.fixups[0].xtrasym = alpha_linkage_symbol; - insn.fixups[0].procsym = alpha_evax_proc->symbol; - insn.nfixups++; - alpha_linkage_symbol = 0; - } -#endif - - emit_insn (&insn); -} - -/* The ret and jcr instructions differ from their instruction - counterparts in that everything can be defaulted. */ - -static void -emit_retjcr (const expressionS *tok, - int ntok, - const void * vopname) -{ - const char *opname = (const char *) vopname; - expressionS newtok[3]; - int r, tokidx = 0; - - if (tokidx < ntok && tok[tokidx].X_op == O_register) - r = regno (tok[tokidx++].X_add_number); - else - r = AXP_REG_ZERO; - - set_tok_reg (newtok[0], r); - - if (tokidx < ntok && - (tok[tokidx].X_op == O_pregister || tok[tokidx].X_op == O_cpregister)) - r = regno (tok[tokidx++].X_add_number); - else - r = AXP_REG_RA; - - set_tok_cpreg (newtok[1], r); - - if (tokidx < ntok) - newtok[2] = tok[tokidx]; - else - set_tok_const (newtok[2], strcmp (opname, "ret") == 0); - - assemble_tokens (opname, newtok, 3, 0); -} - -/* Implement the ldgp macro. */ - -static void -emit_ldgp (const expressionS *tok ATTRIBUTE_UNUSED, - int ntok ATTRIBUTE_UNUSED, - const void * unused ATTRIBUTE_UNUSED) -{ -#ifdef OBJ_AOUT -FIXME -#endif -#if defined(OBJ_ECOFF) || defined(OBJ_ELF) - /* from "ldgp r1,n(r2)", generate "ldah r1,X(R2); lda r1,Y(r1)" - with appropriate constants and relocations. */ - struct alpha_insn insn; - expressionS newtok[3]; - expressionS addend; - -#ifdef OBJ_ECOFF - if (regno (tok[2].X_add_number) == AXP_REG_PV) - ecoff_set_gp_prolog_size (0); -#endif - - newtok[0] = tok[0]; - set_tok_const (newtok[1], 0); - newtok[2] = tok[2]; - - assemble_tokens_to_insn ("ldah", newtok, 3, &insn); - - addend = tok[1]; - -#ifdef OBJ_ECOFF - if (addend.X_op != O_constant) - as_bad (_("can not resolve expression")); - addend.X_op = O_symbol; - addend.X_add_symbol = alpha_gp_symbol; -#endif - - insn.nfixups = 1; - insn.fixups[0].exp = addend; - insn.fixups[0].reloc = BFD_RELOC_ALPHA_GPDISP_HI16; - insn.sequence = next_sequence_num; - - emit_insn (&insn); - - set_tok_preg (newtok[2], tok[0].X_add_number); - - assemble_tokens_to_insn ("lda", newtok, 3, &insn); - -#ifdef OBJ_ECOFF - addend.X_add_number += 4; -#endif - - insn.nfixups = 1; - insn.fixups[0].exp = addend; - insn.fixups[0].reloc = BFD_RELOC_ALPHA_GPDISP_LO16; - insn.sequence = next_sequence_num--; - - emit_insn (&insn); -#endif /* OBJ_ECOFF || OBJ_ELF */ -} - -/* The macro table. */ - -static const struct alpha_macro alpha_macros[] = -{ -/* Load/Store macros. */ - { "lda", emit_lda, NULL, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "ldah", emit_ldah, NULL, - { MACRO_IR, MACRO_EXP, MACRO_EOA } }, - - { "ldl", emit_ir_load, "ldl", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "ldl_l", emit_ir_load, "ldl_l", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "ldq", emit_ir_load, "ldq", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "ldq_l", emit_ir_load, "ldq_l", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "ldq_u", emit_ir_load, "ldq_u", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "ldf", emit_loadstore, "ldf", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "ldg", emit_loadstore, "ldg", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "lds", emit_loadstore, "lds", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "ldt", emit_loadstore, "ldt", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - - { "ldb", emit_ldX, (void *) 0, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "ldbu", emit_ldXu, (void *) 0, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "ldw", emit_ldX, (void *) 1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "ldwu", emit_ldXu, (void *) 1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - - { "uldw", emit_uldX, (void *) 1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "uldwu", emit_uldXu, (void *) 1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "uldl", emit_uldX, (void *) 2, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "uldlu", emit_uldXu, (void *) 2, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "uldq", emit_uldXu, (void *) 3, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - - { "ldgp", emit_ldgp, NULL, - { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA } }, - - { "ldi", emit_lda, NULL, - { MACRO_IR, MACRO_EXP, MACRO_EOA } }, - { "ldil", emit_ldil, NULL, - { MACRO_IR, MACRO_EXP, MACRO_EOA } }, - { "ldiq", emit_lda, NULL, - { MACRO_IR, MACRO_EXP, MACRO_EOA } }, - - { "stl", emit_loadstore, "stl", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "stl_c", emit_loadstore, "stl_c", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "stq", emit_loadstore, "stq", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "stq_c", emit_loadstore, "stq_c", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "stq_u", emit_loadstore, "stq_u", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "stf", emit_loadstore, "stf", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "stg", emit_loadstore, "stg", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "sts", emit_loadstore, "sts", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "stt", emit_loadstore, "stt", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - - { "stb", emit_stX, (void *) 0, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "stw", emit_stX, (void *) 1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "ustw", emit_ustX, (void *) 1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "ustl", emit_ustX, (void *) 2, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - { "ustq", emit_ustX, (void *) 3, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, - -/* Arithmetic macros. */ - - { "sextb", emit_sextX, (void *) 0, - { MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EOA, - /* MACRO_EXP, MACRO_IR, MACRO_EOA */ } }, - { "sextw", emit_sextX, (void *) 1, - { MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EOA, - /* MACRO_EXP, MACRO_IR, MACRO_EOA */ } }, - - { "divl", emit_division, "__divl", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - { "divlu", emit_division, "__divlu", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - { "divq", emit_division, "__divq", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - { "divqu", emit_division, "__divqu", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - { "reml", emit_division, "__reml", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - { "remlu", emit_division, "__remlu", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - { "remq", emit_division, "__remq", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - { "remqu", emit_division, "__remqu", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - - { "jsr", emit_jsrjmp, "jsr", - { MACRO_PIR, MACRO_EXP, MACRO_EOA, - MACRO_PIR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA, - MACRO_EXP, MACRO_EOA } }, - { "jmp", emit_jsrjmp, "jmp", - { MACRO_PIR, MACRO_EXP, MACRO_EOA, - MACRO_PIR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA, - MACRO_EXP, MACRO_EOA } }, - { "ret", emit_retjcr, "ret", - { MACRO_IR, MACRO_EXP, MACRO_EOA, - MACRO_IR, MACRO_EOA, - MACRO_PIR, MACRO_EXP, MACRO_EOA, - MACRO_PIR, MACRO_EOA, - MACRO_EXP, MACRO_EOA, - MACRO_EOA } }, - { "jcr", emit_retjcr, "jcr", - { MACRO_IR, MACRO_EXP, MACRO_EOA, - MACRO_IR, MACRO_EOA, - MACRO_PIR, MACRO_EXP, MACRO_EOA, - MACRO_PIR, MACRO_EOA, - MACRO_EXP, MACRO_EOA, - MACRO_EOA } }, - { "jsr_coroutine", emit_retjcr, "jcr", - { MACRO_IR, MACRO_EXP, MACRO_EOA, - MACRO_IR, MACRO_EOA, - MACRO_PIR, MACRO_EXP, MACRO_EOA, - MACRO_PIR, MACRO_EOA, - MACRO_EXP, MACRO_EOA, - MACRO_EOA } }, -}; - -static const unsigned int alpha_num_macros - = sizeof (alpha_macros) / sizeof (*alpha_macros); - -/* Search forward through all variants of a macro looking for a syntax - match. */ - -static const struct alpha_macro * -find_macro_match (const struct alpha_macro *first_macro, - const expressionS *tok, - int *pntok) - -{ - const struct alpha_macro *macro = first_macro; - int ntok = *pntok; - - do - { - const enum alpha_macro_arg *arg = macro->argsets; - int tokidx = 0; - - while (*arg) - { - switch (*arg) - { - case MACRO_EOA: - if (tokidx == ntok) - return macro; - else - tokidx = 0; - break; - - /* Index register. */ - case MACRO_IR: - if (tokidx >= ntok || tok[tokidx].X_op != O_register - || !is_ir_num (tok[tokidx].X_add_number)) - goto match_failed; - ++tokidx; - break; - - /* Parenthesized index register. */ - case MACRO_PIR: - if (tokidx >= ntok || tok[tokidx].X_op != O_pregister - || !is_ir_num (tok[tokidx].X_add_number)) - goto match_failed; - ++tokidx; - break; - - /* Optional parenthesized index register. */ - case MACRO_OPIR: - if (tokidx < ntok && tok[tokidx].X_op == O_pregister - && is_ir_num (tok[tokidx].X_add_number)) - ++tokidx; - break; - - /* Leading comma with a parenthesized index register. */ - case MACRO_CPIR: - if (tokidx >= ntok || tok[tokidx].X_op != O_cpregister - || !is_ir_num (tok[tokidx].X_add_number)) - goto match_failed; - ++tokidx; - break; - - /* Floating point register. */ - case MACRO_FPR: - if (tokidx >= ntok || tok[tokidx].X_op != O_register - || !is_fpr_num (tok[tokidx].X_add_number)) - goto match_failed; - ++tokidx; - break; - - /* Normal expression. */ - case MACRO_EXP: - if (tokidx >= ntok) - goto match_failed; - switch (tok[tokidx].X_op) - { - case O_illegal: - case O_absent: - case O_register: - case O_pregister: - case O_cpregister: - case O_literal: - case O_lituse_base: - case O_lituse_bytoff: - case O_lituse_jsr: - case O_gpdisp: - case O_gprelhigh: - case O_gprellow: - case O_gprel: - case O_samegp: - goto match_failed; - - default: - break; - } - ++tokidx; - break; - - match_failed: - while (*arg != MACRO_EOA) - ++arg; - tokidx = 0; - break; - } - ++arg; - } - } - while (++macro - alpha_macros < (int) alpha_num_macros - && !strcmp (macro->name, first_macro->name)); - - return NULL; -} - -/* Given an opcode name and a pre-tokenized set of arguments, take the - opcode all the way through emission. */ - -static void -assemble_tokens (const char *opname, - const expressionS *tok, - int ntok, - int local_macros_on) -{ - int found_something = 0; - const struct alpha_opcode *opcode; - const struct alpha_macro *macro; - int cpumatch = 1; - extended_bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED; - -#ifdef RELOC_OP_P - /* If a user-specified relocation is present, this is not a macro. */ - if (ntok && USER_RELOC_P (tok[ntok - 1].X_op)) - { - reloc = ALPHA_RELOC_TABLE (tok[ntok - 1].X_op)->reloc; - ntok--; - } - else -#endif - if (local_macros_on) - { - macro = ((const struct alpha_macro *) - hash_find (alpha_macro_hash, opname)); - if (macro) - { - found_something = 1; - macro = find_macro_match (macro, tok, &ntok); - if (macro) - { - (*macro->emit) (tok, ntok, macro->arg); - return; - } - } - } - - /* Search opcodes. */ - opcode = (const struct alpha_opcode *) hash_find (alpha_opcode_hash, opname); - if (opcode) - { - found_something = 1; - opcode = find_opcode_match (opcode, tok, &ntok, &cpumatch); - if (opcode) - { - struct alpha_insn insn; - assemble_insn (opcode, tok, ntok, &insn, reloc); - - /* Copy the sequence number for the reloc from the reloc token. */ - if (reloc != BFD_RELOC_UNUSED) - insn.sequence = tok[ntok].X_add_number; - - emit_insn (&insn); - return; - } - } - - if (found_something) - { - if (cpumatch) - as_bad (_("inappropriate arguments for opcode `%s'"), opname); - else - as_bad (_("opcode `%s' not supported for target %s"), opname, - alpha_target_name); - } - else - as_bad (_("unknown opcode `%s'"), opname); -} - -#ifdef OBJ_EVAX - -/* Add sym+addend to link pool. - Return offset from curent procedure value (pv) to entry in link pool. - - Add new fixup only if offset isn't 16bit. */ - -static symbolS * -add_to_link_pool (symbolS *sym, offsetT addend) -{ - symbolS *basesym; - segT current_section = now_seg; - int current_subsec = now_subseg; - char *p; - segment_info_type *seginfo = seg_info (alpha_link_section); - fixS *fixp; - symbolS *linksym, *expsym; - expressionS e; - - basesym = alpha_evax_proc->symbol; - - /* @@ This assumes all entries in a given section will be of the same - size... Probably correct, but unwise to rely on. */ - /* This must always be called with the same subsegment. */ - - if (seginfo->frchainP) - for (fixp = seginfo->frchainP->fix_root; - fixp != (fixS *) NULL; - fixp = fixp->fx_next) - { - if (fixp->fx_addsy == sym - && fixp->fx_offset == (valueT)addend - && fixp->tc_fix_data.info - && fixp->tc_fix_data.info->sym - && fixp->tc_fix_data.info->sym->sy_value.X_op_symbol == basesym) - return fixp->tc_fix_data.info->sym; - } - - /* Not found, add a new entry. */ - subseg_set (alpha_link_section, 0); - linksym = symbol_new - (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now); - p = frag_more (8); - memset (p, 0, 8); - - /* Create a symbol for 'basesym - linksym' (offset of the added entry). */ - e.X_op = O_subtract; - e.X_add_symbol = linksym; - e.X_op_symbol = basesym; - e.X_add_number = 0; - expsym = make_expr_symbol (&e); - - /* Create a fixup for the entry. */ - fixp = fix_new - (frag_now, p - frag_now->fr_literal, 8, sym, addend, 0, BFD_RELOC_64); - fixp->tc_fix_data.info = get_alpha_reloc_tag (next_sequence_num--); - fixp->tc_fix_data.info->sym = expsym; - - subseg_set (current_section, current_subsec); - - /* Return the symbol. */ - return expsym; -} -#endif /* OBJ_EVAX */ - -/* Assembler directives. */ - -/* Handle the .text pseudo-op. This is like the usual one, but it - clears alpha_insn_label and restores auto alignment. */ - -static void -s_alpha_text (int i) -{ -#ifdef OBJ_ELF - obj_elf_text (i); -#else - s_text (i); -#endif -#ifdef OBJ_EVAX - { - symbolS * symbolP; - - symbolP = symbol_find (".text"); - if (symbolP == NULL) - { - symbolP = symbol_make (".text"); - S_SET_SEGMENT (symbolP, text_section); - symbol_table_insert (symbolP); - } - } -#endif - alpha_insn_label = NULL; - alpha_auto_align_on = 1; - alpha_current_align = 0; -} - -/* Handle the .data pseudo-op. This is like the usual one, but it - clears alpha_insn_label and restores auto alignment. */ - -static void -s_alpha_data (int i) -{ -#ifdef OBJ_ELF - obj_elf_data (i); -#else - s_data (i); -#endif - alpha_insn_label = NULL; - alpha_auto_align_on = 1; - alpha_current_align = 0; -} - -#if defined (OBJ_ECOFF) || defined (OBJ_EVAX) - -/* Handle the OSF/1 and openVMS .comm pseudo quirks. */ - -static void -s_alpha_comm (int ignore ATTRIBUTE_UNUSED) -{ - char *name; - char c; - char *p; - offsetT size; - symbolS *symbolP; -#ifdef OBJ_EVAX - offsetT temp; - int log_align = 0; -#endif - - name = input_line_pointer; - c = get_symbol_end (); - - /* Just after name is now '\0'. */ - p = input_line_pointer; - *p = c; - - SKIP_WHITESPACE (); - - /* Alpha OSF/1 compiler doesn't provide the comma, gcc does. */ - if (*input_line_pointer == ',') - { - input_line_pointer++; - SKIP_WHITESPACE (); - } - if ((size = get_absolute_expression ()) < 0) - { - as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) size); - ignore_rest_of_line (); - return; - } - - *p = 0; - symbolP = symbol_find_or_make (name); - *p = c; - - if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) - { - as_bad (_("Ignoring attempt to re-define symbol")); - ignore_rest_of_line (); - return; - } - -#ifdef OBJ_EVAX - if (*input_line_pointer != ',') - temp = 8; /* Default alignment. */ - else - { - input_line_pointer++; - SKIP_WHITESPACE (); - temp = get_absolute_expression (); - } - - /* ??? Unlike on OSF/1, the alignment factor is not in log units. */ - while ((temp >>= 1) != 0) - ++log_align; - - if (*input_line_pointer == ',') - { - /* Extended form of the directive - - .comm symbol, size, alignment, section - - where the "common" semantics is transferred to the section. - The symbol is effectively an alias for the section name. */ - - segT sec; - char *sec_name; - symbolS *sec_symbol; - segT current_seg = now_seg; - subsegT current_subseg = now_subseg; - int cur_size; - - input_line_pointer++; - SKIP_WHITESPACE (); - sec_name = s_alpha_section_name (); - sec_symbol = symbol_find_or_make (sec_name); - sec = subseg_new (sec_name, 0); - S_SET_SEGMENT (sec_symbol, sec); - symbol_get_bfdsym (sec_symbol)->flags |= BSF_SECTION_SYM; - bfd_vms_set_section_flags (stdoutput, sec, 0, - EGPS__V_OVR | EGPS__V_GBL | EGPS__V_NOMOD); - record_alignment (sec, log_align); - - /* Reuse stab_string_size to store the size of the section. */ - cur_size = seg_info (sec)->stabu.stab_string_size; - if ((int) size > cur_size) - { - char *pfrag - = frag_var (rs_fill, 1, 1, (relax_substateT)0, NULL, - (valueT)size - (valueT)cur_size, NULL); - *pfrag = 0; - seg_info (sec)->stabu.stab_string_size = (int)size; - } - - S_SET_SEGMENT (symbolP, sec); - - subseg_set (current_seg, current_subseg); - } - else - { - /* Regular form of the directive - - .comm symbol, size, alignment - - where the "common" semantics in on the symbol. - These symbols are assembled in the .bss section. */ - - char *pfrag; - segT current_seg = now_seg; - subsegT current_subseg = now_subseg; - - subseg_set (bss_section, 1); - frag_align (log_align, 0, 0); - record_alignment (bss_section, log_align); - - symbol_set_frag (symbolP, frag_now); - pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP, - size, NULL); - *pfrag = 0; - - S_SET_SEGMENT (symbolP, bss_section); - - subseg_set (current_seg, current_subseg); - } -#endif - - if (S_GET_VALUE (symbolP)) - { - if (S_GET_VALUE (symbolP) != (valueT) size) - as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."), - S_GET_NAME (symbolP), - (long) S_GET_VALUE (symbolP), - (long) size); - } - else - { -#ifndef OBJ_EVAX - S_SET_VALUE (symbolP, (valueT) size); -#endif - S_SET_EXTERNAL (symbolP); - } - -#ifndef OBJ_EVAX - know (symbolP->sy_frag == &zero_address_frag); -#endif - demand_empty_rest_of_line (); -} - -#endif /* ! OBJ_ELF */ - -#ifdef OBJ_ECOFF - -/* Handle the .rdata pseudo-op. This is like the usual one, but it - clears alpha_insn_label and restores auto alignment. */ - -static void -s_alpha_rdata (int ignore ATTRIBUTE_UNUSED) -{ - get_absolute_expression (); - subseg_new (".rdata", 0); - demand_empty_rest_of_line (); - alpha_insn_label = NULL; - alpha_auto_align_on = 1; - alpha_current_align = 0; -} - -#endif - -#ifdef OBJ_ECOFF - -/* Handle the .sdata pseudo-op. This is like the usual one, but it - clears alpha_insn_label and restores auto alignment. */ - -static void -s_alpha_sdata (int ignore ATTRIBUTE_UNUSED) -{ - get_absolute_expression (); - subseg_new (".sdata", 0); - demand_empty_rest_of_line (); - alpha_insn_label = NULL; - alpha_auto_align_on = 1; - alpha_current_align = 0; -} -#endif - -#ifdef OBJ_ELF -struct alpha_elf_frame_data -{ - symbolS *func_sym; - symbolS *func_end_sym; - symbolS *prologue_sym; - unsigned int mask; - unsigned int fmask; - int fp_regno; - int ra_regno; - offsetT frame_size; - offsetT mask_offset; - offsetT fmask_offset; - - struct alpha_elf_frame_data *next; -}; - -static struct alpha_elf_frame_data *all_frame_data; -static struct alpha_elf_frame_data **plast_frame_data = &all_frame_data; -static struct alpha_elf_frame_data *cur_frame_data; - -/* Handle the .section pseudo-op. This is like the usual one, but it - clears alpha_insn_label and restores auto alignment. */ - -static void -s_alpha_section (int ignore ATTRIBUTE_UNUSED) -{ - obj_elf_section (ignore); - - alpha_insn_label = NULL; - alpha_auto_align_on = 1; - alpha_current_align = 0; -} - -static void -s_alpha_ent (int dummy ATTRIBUTE_UNUSED) -{ - if (ECOFF_DEBUGGING) - ecoff_directive_ent (0); - else - { - char *name, name_end; - name = input_line_pointer; - name_end = get_symbol_end (); - - if (! is_name_beginner (*name)) - { - as_warn (_(".ent directive has no name")); - *input_line_pointer = name_end; - } - else - { - symbolS *sym; - - if (cur_frame_data) - as_warn (_("nested .ent directives")); - - sym = symbol_find_or_make (name); - symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION; - - cur_frame_data = (struct alpha_elf_frame_data *) - calloc (1, sizeof (*cur_frame_data)); - cur_frame_data->func_sym = sym; - - /* Provide sensible defaults. */ - cur_frame_data->fp_regno = 30; /* sp */ - cur_frame_data->ra_regno = 26; /* ra */ - - *plast_frame_data = cur_frame_data; - plast_frame_data = &cur_frame_data->next; - - /* The .ent directive is sometimes followed by a number. Not sure - what it really means, but ignore it. */ - *input_line_pointer = name_end; - SKIP_WHITESPACE (); - if (*input_line_pointer == ',') - { - input_line_pointer++; - SKIP_WHITESPACE (); - } - if (ISDIGIT (*input_line_pointer) || *input_line_pointer == '-') - (void) get_absolute_expression (); - } - demand_empty_rest_of_line (); - } -} - -static void -s_alpha_end (int dummy ATTRIBUTE_UNUSED) -{ - if (ECOFF_DEBUGGING) - ecoff_directive_end (0); - else - { - char *name, name_end; - name = input_line_pointer; - name_end = get_symbol_end (); - - if (! is_name_beginner (*name)) - { - as_warn (_(".end directive has no name")); - *input_line_pointer = name_end; - } - else - { - symbolS *sym; - - sym = symbol_find (name); - if (!cur_frame_data) - as_warn (_(".end directive without matching .ent")); - else if (sym != cur_frame_data->func_sym) - as_warn (_(".end directive names different symbol than .ent")); - - /* Create an expression to calculate the size of the function. */ - if (sym && cur_frame_data) - { - OBJ_SYMFIELD_TYPE *obj = symbol_get_obj (sym); - expressionS *exp = (expressionS *) xmalloc (sizeof (expressionS)); - - obj->size = exp; - exp->X_op = O_subtract; - exp->X_add_symbol = symbol_temp_new_now (); - exp->X_op_symbol = sym; - exp->X_add_number = 0; - - cur_frame_data->func_end_sym = exp->X_add_symbol; - } - - cur_frame_data = NULL; - - *input_line_pointer = name_end; - } - demand_empty_rest_of_line (); - } -} - -static void -s_alpha_mask (int fp) -{ - if (ECOFF_DEBUGGING) - { - if (fp) - ecoff_directive_fmask (0); - else - ecoff_directive_mask (0); - } - else - { - long val; - offsetT offset; - - if (!cur_frame_data) - { - if (fp) - as_warn (_(".fmask outside of .ent")); - else - as_warn (_(".mask outside of .ent")); - discard_rest_of_line (); - return; - } - - if (get_absolute_expression_and_terminator (&val) != ',') - { - if (fp) - as_warn (_("bad .fmask directive")); - else - as_warn (_("bad .mask directive")); - --input_line_pointer; - discard_rest_of_line (); - return; - } - - offset = get_absolute_expression (); - demand_empty_rest_of_line (); - - if (fp) - { - cur_frame_data->fmask = val; - cur_frame_data->fmask_offset = offset; - } - else - { - cur_frame_data->mask = val; - cur_frame_data->mask_offset = offset; - } - } -} - -static void -s_alpha_frame (int dummy ATTRIBUTE_UNUSED) -{ - if (ECOFF_DEBUGGING) - ecoff_directive_frame (0); - else - { - long val; - - if (!cur_frame_data) - { - as_warn (_(".frame outside of .ent")); - discard_rest_of_line (); - return; - } - - cur_frame_data->fp_regno = tc_get_register (1); - - SKIP_WHITESPACE (); - if (*input_line_pointer++ != ',' - || get_absolute_expression_and_terminator (&val) != ',') - { - as_warn (_("bad .frame directive")); - --input_line_pointer; - discard_rest_of_line (); - return; - } - cur_frame_data->frame_size = val; - - cur_frame_data->ra_regno = tc_get_register (0); - - /* Next comes the "offset of saved $a0 from $sp". In gcc terms - this is current_function_pretend_args_size. There's no place - to put this value, so ignore it. */ - s_ignore (42); - } -} - -static void -s_alpha_prologue (int ignore ATTRIBUTE_UNUSED) -{ - symbolS *sym; - int arg; - - arg = get_absolute_expression (); - demand_empty_rest_of_line (); - alpha_prologue_label = symbol_new - (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now); - - if (ECOFF_DEBUGGING) - sym = ecoff_get_cur_proc_sym (); - else - sym = cur_frame_data ? cur_frame_data->func_sym : NULL; - - if (sym == NULL) - { - as_bad (_(".prologue directive without a preceding .ent directive")); - return; - } - - switch (arg) - { - case 0: /* No PV required. */ - S_SET_OTHER (sym, STO_ALPHA_NOPV - | (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD)); - break; - case 1: /* Std GP load. */ - S_SET_OTHER (sym, STO_ALPHA_STD_GPLOAD - | (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD)); - break; - case 2: /* Non-std use of PV. */ - break; - - default: - as_bad (_("Invalid argument %d to .prologue."), arg); - break; - } - - if (cur_frame_data) - cur_frame_data->prologue_sym = symbol_temp_new_now (); -} - -static char *first_file_directive; - -static void -s_alpha_file (int ignore ATTRIBUTE_UNUSED) -{ - /* Save the first .file directive we see, so that we can change our - minds about whether ecoff debugging should or shouldn't be enabled. */ - if (alpha_flag_mdebug < 0 && ! first_file_directive) - { - char *start = input_line_pointer; - size_t len; - - discard_rest_of_line (); - - len = input_line_pointer - start; - first_file_directive = (char *) xmalloc (len + 1); - memcpy (first_file_directive, start, len); - first_file_directive[len] = '\0'; - - input_line_pointer = start; - } - - if (ECOFF_DEBUGGING) - ecoff_directive_file (0); - else - dwarf2_directive_file (0); -} - -static void -s_alpha_loc (int ignore ATTRIBUTE_UNUSED) -{ - if (ECOFF_DEBUGGING) - ecoff_directive_loc (0); - else - dwarf2_directive_loc (0); -} - -static void -s_alpha_stab (int n) -{ - /* If we've been undecided about mdebug, make up our minds in favour. */ - if (alpha_flag_mdebug < 0) - { - segT sec = subseg_new (".mdebug", 0); - bfd_set_section_flags (stdoutput, sec, SEC_HAS_CONTENTS | SEC_READONLY); - bfd_set_section_alignment (stdoutput, sec, 3); - - ecoff_read_begin_hook (); - - if (first_file_directive) - { - char *save_ilp = input_line_pointer; - input_line_pointer = first_file_directive; - ecoff_directive_file (0); - input_line_pointer = save_ilp; - free (first_file_directive); - } - - alpha_flag_mdebug = 1; - } - s_stab (n); -} - -static void -s_alpha_coff_wrapper (int which) -{ - static void (* const fns[]) (int) = { - ecoff_directive_begin, - ecoff_directive_bend, - ecoff_directive_def, - ecoff_directive_dim, - ecoff_directive_endef, - ecoff_directive_scl, - ecoff_directive_tag, - ecoff_directive_val, - }; - - gas_assert (which >= 0 && which < (int) (sizeof (fns)/sizeof (*fns))); - - if (ECOFF_DEBUGGING) - (*fns[which]) (0); - else - { - as_bad (_("ECOFF debugging is disabled.")); - ignore_rest_of_line (); - } -} - -/* Called at the end of assembly. Here we emit unwind info for frames - unless the compiler has done it for us. */ - -void -alpha_elf_md_end (void) -{ - struct alpha_elf_frame_data *p; - - if (cur_frame_data) - as_warn (_(".ent directive without matching .end")); - - /* If someone has generated the unwind info themselves, great. */ - if (bfd_get_section_by_name (stdoutput, ".eh_frame") != NULL) - return; - - /* ??? In theory we could look for functions for which we have - generated unwind info via CFI directives, and those we have not. - Those we have not could still get their unwind info from here. - For now, do nothing if we've seen any CFI directives. Note that - the above test will not trigger, as we've not emitted data yet. */ - if (all_fde_data != NULL) - return; - - /* Generate .eh_frame data for the unwind directives specified. */ - for (p = all_frame_data; p ; p = p->next) - if (p->prologue_sym) - { - /* Create a temporary symbol at the same location as our - function symbol. This prevents problems with globals. */ - cfi_new_fde (symbol_temp_new (S_GET_SEGMENT (p->func_sym), - S_GET_VALUE (p->func_sym), - symbol_get_frag (p->func_sym))); - - cfi_set_return_column (p->ra_regno); - cfi_add_CFA_def_cfa_register (30); - if (p->fp_regno != 30 || p->mask || p->fmask || p->frame_size) - { - unsigned int mask; - offsetT offset; - - cfi_add_advance_loc (p->prologue_sym); - - if (p->fp_regno != 30) - if (p->frame_size != 0) - cfi_add_CFA_def_cfa (p->fp_regno, p->frame_size); - else - cfi_add_CFA_def_cfa_register (p->fp_regno); - else if (p->frame_size != 0) - cfi_add_CFA_def_cfa_offset (p->frame_size); - - mask = p->mask; - offset = p->mask_offset; - - /* Recall that $26 is special-cased and stored first. */ - if ((mask >> 26) & 1) - { - cfi_add_CFA_offset (26, offset); - offset += 8; - mask &= ~(1 << 26); - } - while (mask) - { - unsigned int i; - i = mask & -mask; - mask ^= i; - i = ffs (i) - 1; - - cfi_add_CFA_offset (i, offset); - offset += 8; - } - - mask = p->fmask; - offset = p->fmask_offset; - while (mask) - { - unsigned int i; - i = mask & -mask; - mask ^= i; - i = ffs (i) - 1; - - cfi_add_CFA_offset (i + 32, offset); - offset += 8; - } - } - - cfi_end_fde (p->func_end_sym); - } -} - -static void -s_alpha_usepv (int unused ATTRIBUTE_UNUSED) -{ - char *name, name_end; - char *which, which_end; - symbolS *sym; - int other; - - name = input_line_pointer; - name_end = get_symbol_end (); - - if (! is_name_beginner (*name)) - { - as_bad (_(".usepv directive has no name")); - *input_line_pointer = name_end; - ignore_rest_of_line (); - return; - } - - sym = symbol_find_or_make (name); - *input_line_pointer++ = name_end; - - if (name_end != ',') - { - as_bad (_(".usepv directive has no type")); - ignore_rest_of_line (); - return; - } - - SKIP_WHITESPACE (); - which = input_line_pointer; - which_end = get_symbol_end (); - - if (strcmp (which, "no") == 0) - other = STO_ALPHA_NOPV; - else if (strcmp (which, "std") == 0) - other = STO_ALPHA_STD_GPLOAD; - else - { - as_bad (_("unknown argument for .usepv")); - other = 0; - } - - *input_line_pointer = which_end; - demand_empty_rest_of_line (); - - S_SET_OTHER (sym, other | (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD)); -} -#endif /* OBJ_ELF */ - -/* Standard calling conventions leaves the CFA at $30 on entry. */ - -void -alpha_cfi_frame_initial_instructions (void) -{ - cfi_add_CFA_def_cfa_register (30); -} - -#ifdef OBJ_EVAX - -/* Get name of section. */ -static char * -s_alpha_section_name (void) -{ - char *name; - - SKIP_WHITESPACE (); - if (*input_line_pointer == '"') - { - int dummy; - - name = demand_copy_C_string (&dummy); - if (name == NULL) - { - ignore_rest_of_line (); - return NULL; - } - } - else - { - char *end = input_line_pointer; - - while (0 == strchr ("\n\t,; ", *end)) - end++; - if (end == input_line_pointer) - { - as_warn (_("missing name")); - ignore_rest_of_line (); - return NULL; - } - - name = xmalloc (end - input_line_pointer + 1); - memcpy (name, input_line_pointer, end - input_line_pointer); - name[end - input_line_pointer] = '\0'; - input_line_pointer = end; - } - SKIP_WHITESPACE (); - return name; -} - -/* Put clear/set flags in one flagword. The LSBs are flags to be set, - the MSBs are the flags to be cleared. */ - -#define EGPS__V_NO_SHIFT 16 -#define EGPS__V_MASK 0xffff - -/* Parse one VMS section flag. */ - -static flagword -s_alpha_section_word (char *str, size_t len) -{ - int no = 0; - flagword flag = 0; - - if (len == 5 && strncmp (str, "NO", 2) == 0) - { - no = 1; - str += 2; - len -= 2; - } - - if (len == 3) - { - if (strncmp (str, "PIC", 3) == 0) - flag = EGPS__V_PIC; - else if (strncmp (str, "LIB", 3) == 0) - flag = EGPS__V_LIB; - else if (strncmp (str, "OVR", 3) == 0) - flag = EGPS__V_OVR; - else if (strncmp (str, "REL", 3) == 0) - flag = EGPS__V_REL; - else if (strncmp (str, "GBL", 3) == 0) - flag = EGPS__V_GBL; - else if (strncmp (str, "SHR", 3) == 0) - flag = EGPS__V_SHR; - else if (strncmp (str, "EXE", 3) == 0) - flag = EGPS__V_EXE; - else if (strncmp (str, "WRT", 3) == 0) - flag = EGPS__V_WRT; - else if (strncmp (str, "VEC", 3) == 0) - flag = EGPS__V_VEC; - else if (strncmp (str, "MOD", 3) == 0) - { - flag = no ? EGPS__V_NOMOD : EGPS__V_NOMOD << EGPS__V_NO_SHIFT; - no = 0; - } - else if (strncmp (str, "COM", 3) == 0) - flag = EGPS__V_COM; - } - - if (flag == 0) - { - char c = str[len]; - str[len] = 0; - as_warn (_("unknown section attribute %s"), str); - str[len] = c; - return 0; - } - - if (no) - return flag << EGPS__V_NO_SHIFT; - else - return flag; -} - -/* Handle the section specific pseudo-op. */ - -#define EVAX_SECTION_COUNT 5 - -static char *section_name[EVAX_SECTION_COUNT + 1] = - { "NULL", ".rdata", ".comm", ".link", ".ctors", ".dtors" }; - -static void -s_alpha_section (int secid) -{ - char *name, *beg; - segT sec; - flagword vms_flags = 0; - symbolS *symbol; - - if (secid == 0) - { - name = s_alpha_section_name (); - if (name == NULL) - return; - sec = subseg_new (name, 0); - if (*input_line_pointer == ',') - { - /* Skip the comma. */ - ++input_line_pointer; - SKIP_WHITESPACE (); - - do - { - char c; - - SKIP_WHITESPACE (); - beg = input_line_pointer; - c = get_symbol_end (); - *input_line_pointer = c; - - vms_flags |= s_alpha_section_word (beg, input_line_pointer - beg); - - SKIP_WHITESPACE (); - } - while (*input_line_pointer++ == ','); - --input_line_pointer; - } - - symbol = symbol_find_or_make (name); - S_SET_SEGMENT (symbol, sec); - symbol_get_bfdsym (symbol)->flags |= BSF_SECTION_SYM; - bfd_vms_set_section_flags - (stdoutput, sec, - (vms_flags >> EGPS__V_NO_SHIFT) & EGPS__V_MASK, - vms_flags & EGPS__V_MASK); - } - else - { - get_absolute_expression (); - subseg_new (section_name[secid], 0); - } - - demand_empty_rest_of_line (); - alpha_insn_label = NULL; - alpha_auto_align_on = 1; - alpha_current_align = 0; -} - -static void -s_alpha_literals (int ignore ATTRIBUTE_UNUSED) -{ - subseg_new (".literals", 0); - demand_empty_rest_of_line (); - alpha_insn_label = NULL; - alpha_auto_align_on = 1; - alpha_current_align = 0; -} - -/* Parse .ent directives. */ - -static void -s_alpha_ent (int ignore ATTRIBUTE_UNUSED) -{ - symbolS *symbol; - expressionS symexpr; - - if (alpha_evax_proc != NULL) - as_bad (_("previous .ent not closed by a .end")); - - alpha_evax_proc = &alpha_evax_proc_data; - - alpha_evax_proc->pdsckind = 0; - alpha_evax_proc->framereg = -1; - alpha_evax_proc->framesize = 0; - alpha_evax_proc->rsa_offset = 0; - alpha_evax_proc->ra_save = AXP_REG_RA; - alpha_evax_proc->fp_save = -1; - alpha_evax_proc->imask = 0; - alpha_evax_proc->fmask = 0; - alpha_evax_proc->prologue = 0; - alpha_evax_proc->type = 0; - alpha_evax_proc->handler = 0; - alpha_evax_proc->handler_data = 0; - - expression (&symexpr); - - if (symexpr.X_op != O_symbol) - { - as_fatal (_(".ent directive has no symbol")); - demand_empty_rest_of_line (); - return; - } - - symbol = make_expr_symbol (&symexpr); - symbol_get_bfdsym (symbol)->flags |= BSF_FUNCTION; - alpha_evax_proc->symbol = symbol; - - demand_empty_rest_of_line (); -} - -static void -s_alpha_handler (int is_data) -{ - if (is_data) - alpha_evax_proc->handler_data = get_absolute_expression (); - else - { - char *name, name_end; - name = input_line_pointer; - name_end = get_symbol_end (); - - if (! is_name_beginner (*name)) - { - as_warn (_(".handler directive has no name")); - *input_line_pointer = name_end; - } - else - { - symbolS *sym; - - sym = symbol_find_or_make (name); - symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION; - alpha_evax_proc->handler = sym; - *input_line_pointer = name_end; - } - } - demand_empty_rest_of_line (); -} - -/* Parse .frame <framreg>,<framesize>,RA,<rsa_offset> directives. */ - -static void -s_alpha_frame (int ignore ATTRIBUTE_UNUSED) -{ - long val; - int ra; - - alpha_evax_proc->framereg = tc_get_register (1); - - SKIP_WHITESPACE (); - if (*input_line_pointer++ != ',' - || get_absolute_expression_and_terminator (&val) != ',') - { - as_warn (_("Bad .frame directive 1./2. param")); - --input_line_pointer; - demand_empty_rest_of_line (); - return; - } - - alpha_evax_proc->framesize = val; - - ra = tc_get_register (1); - if (ra != AXP_REG_RA) - as_warn (_("Bad RA (%d) register for .frame"), ra); - - SKIP_WHITESPACE (); - if (*input_line_pointer++ != ',') - { - as_warn (_("Bad .frame directive 3./4. param")); - --input_line_pointer; - demand_empty_rest_of_line (); - return; - } - alpha_evax_proc->rsa_offset = get_absolute_expression (); -} - -/* Parse .prologue. */ - -static void -s_alpha_prologue (int ignore ATTRIBUTE_UNUSED) -{ - demand_empty_rest_of_line (); - alpha_prologue_label = symbol_new - (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now); -} - -/* Parse .pdesc <entry_name>,{null|stack|reg} - Insert a procedure descriptor. */ - -static void -s_alpha_pdesc (int ignore ATTRIBUTE_UNUSED) -{ - char *name; - char name_end; - register char *p; - expressionS exp; - symbolS *entry_sym; - const char *entry_sym_name; - const char *pdesc_sym_name; - fixS *fixp; - size_t len; - - if (now_seg != alpha_link_section) - { - as_bad (_(".pdesc directive not in link (.link) section")); - return; - } - - expression (&exp); - if (exp.X_op != O_symbol) - { - as_bad (_(".pdesc directive has no entry symbol")); - return; - } - - entry_sym = make_expr_symbol (&exp); - entry_sym_name = S_GET_NAME (entry_sym); - - /* Strip "..en". */ - len = strlen (entry_sym_name); - if (len < 4 || strcmp (entry_sym_name + len - 4, "..en") != 0) - { - as_bad (_(".pdesc has a bad entry symbol")); - return; - } - len -= 4; - pdesc_sym_name = S_GET_NAME (alpha_evax_proc->symbol); - - if (!alpha_evax_proc - || !S_IS_DEFINED (alpha_evax_proc->symbol) - || strlen (pdesc_sym_name) != len - || memcmp (entry_sym_name, pdesc_sym_name, len) != 0) - { - as_fatal (_(".pdesc doesn't match with last .ent")); - return; - } - - /* Define pdesc symbol. */ - symbol_set_value_now (alpha_evax_proc->symbol); - - /* Save bfd symbol of proc entry in function symbol. */ - ((struct evax_private_udata_struct *) - symbol_get_bfdsym (alpha_evax_proc->symbol)->udata.p)->enbsym - = symbol_get_bfdsym (entry_sym); - - SKIP_WHITESPACE (); - if (*input_line_pointer++ != ',') - { - as_warn (_("No comma after .pdesc <entryname>")); - demand_empty_rest_of_line (); - return; - } - - SKIP_WHITESPACE (); - name = input_line_pointer; - name_end = get_symbol_end (); - - if (strncmp (name, "stack", 5) == 0) - alpha_evax_proc->pdsckind = PDSC_S_K_KIND_FP_STACK; - - else if (strncmp (name, "reg", 3) == 0) - alpha_evax_proc->pdsckind = PDSC_S_K_KIND_FP_REGISTER; - - else if (strncmp (name, "null", 4) == 0) - alpha_evax_proc->pdsckind = PDSC_S_K_KIND_NULL; - - else - { - as_fatal (_("unknown procedure kind")); - demand_empty_rest_of_line (); - return; - } - - *input_line_pointer = name_end; - demand_empty_rest_of_line (); - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - frag_align (3, 0, 0); - p = frag_more (16); - fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0); - fixp->fx_done = 1; - - *p = alpha_evax_proc->pdsckind - | ((alpha_evax_proc->framereg == 29) ? PDSC_S_M_BASE_REG_IS_FP : 0) - | ((alpha_evax_proc->handler) ? PDSC_S_M_HANDLER_VALID : 0) - | ((alpha_evax_proc->handler_data) ? PDSC_S_M_HANDLER_DATA_VALID : 0); - *(p + 1) = PDSC_S_M_NATIVE | PDSC_S_M_NO_JACKET; - - switch (alpha_evax_proc->pdsckind) - { - case PDSC_S_K_KIND_NULL: - *(p + 2) = 0; - *(p + 3) = 0; - break; - case PDSC_S_K_KIND_FP_REGISTER: - *(p + 2) = alpha_evax_proc->fp_save; - *(p + 3) = alpha_evax_proc->ra_save; - break; - case PDSC_S_K_KIND_FP_STACK: - md_number_to_chars (p + 2, (valueT) alpha_evax_proc->rsa_offset, 2); - break; - default: /* impossible */ - break; - } - - *(p + 4) = 0; - *(p + 5) = alpha_evax_proc->type & 0x0f; - - /* Signature offset. */ - md_number_to_chars (p + 6, (valueT) 0, 2); - - fix_new_exp (frag_now, p - frag_now->fr_literal + 8, - 8, &exp, 0, BFD_RELOC_64); - - if (alpha_evax_proc->pdsckind == PDSC_S_K_KIND_NULL) - return; - - /* pdesc+16: Size. */ - p = frag_more (6); - md_number_to_chars (p, (valueT) alpha_evax_proc->framesize, 4); - md_number_to_chars (p + 4, (valueT) 0, 2); - - /* Entry length. */ - exp.X_op = O_subtract; - exp.X_add_symbol = alpha_prologue_label; - exp.X_op_symbol = entry_sym; - emit_expr (&exp, 2); - - if (alpha_evax_proc->pdsckind == PDSC_S_K_KIND_FP_REGISTER) - return; - - /* pdesc+24: register masks. */ - p = frag_more (8); - md_number_to_chars (p, alpha_evax_proc->imask, 4); - md_number_to_chars (p + 4, alpha_evax_proc->fmask, 4); - - if (alpha_evax_proc->handler) - { - p = frag_more (8); - fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, - alpha_evax_proc->handler, 0, 0, BFD_RELOC_64); - } - - if (alpha_evax_proc->handler_data) - { - p = frag_more (8); - md_number_to_chars (p, alpha_evax_proc->handler_data, 8); - } -} - -/* Support for crash debug on vms. */ - -static void -s_alpha_name (int ignore ATTRIBUTE_UNUSED) -{ - char *p; - expressionS exp; - - if (now_seg != alpha_link_section) - { - as_bad (_(".name directive not in link (.link) section")); - demand_empty_rest_of_line (); - return; - } - - expression (&exp); - if (exp.X_op != O_symbol) - { - as_warn (_(".name directive has no symbol")); - demand_empty_rest_of_line (); - return; - } - - demand_empty_rest_of_line (); - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - frag_align (3, 0, 0); - p = frag_more (8); - - fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &exp, 0, BFD_RELOC_64); -} - -/* Parse .linkage <symbol>. - Create a linkage pair relocation. */ - -static void -s_alpha_linkage (int ignore ATTRIBUTE_UNUSED) -{ - expressionS exp; - char *p; - fixS *fixp; - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - expression (&exp); - if (exp.X_op != O_symbol) - { - as_fatal (_("No symbol after .linkage")); - } - else - { - struct alpha_linkage_fixups *linkage_fixup; - - p = frag_more (LKP_S_K_SIZE); - memset (p, 0, LKP_S_K_SIZE); - fixp = fix_new_exp - (frag_now, p - frag_now->fr_literal, LKP_S_K_SIZE, &exp, 0, - BFD_RELOC_ALPHA_LINKAGE); - - if (alpha_insn_label == NULL) - alpha_insn_label = symbol_new - (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now); - - /* Create a linkage element. */ - linkage_fixup = (struct alpha_linkage_fixups *) - xmalloc (sizeof (struct alpha_linkage_fixups)); - linkage_fixup->fixp = fixp; - linkage_fixup->next = NULL; - linkage_fixup->label = alpha_insn_label; - - /* Append it to the list. */ - if (alpha_linkage_fixup_root == NULL) - alpha_linkage_fixup_root = linkage_fixup; - else - alpha_linkage_fixup_tail->next = linkage_fixup; - alpha_linkage_fixup_tail = linkage_fixup; - } - demand_empty_rest_of_line (); -} - -/* Parse .code_address <symbol>. - Create a code address relocation. */ - -static void -s_alpha_code_address (int ignore ATTRIBUTE_UNUSED) -{ - expressionS exp; - char *p; - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - expression (&exp); - if (exp.X_op != O_symbol) - as_fatal (_("No symbol after .code_address")); - else - { - p = frag_more (8); - memset (p, 0, 8); - fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &exp, 0,\ - BFD_RELOC_ALPHA_CODEADDR); - } - demand_empty_rest_of_line (); -} - -static void -s_alpha_fp_save (int ignore ATTRIBUTE_UNUSED) -{ - alpha_evax_proc->fp_save = tc_get_register (1); - - demand_empty_rest_of_line (); -} - -static void -s_alpha_mask (int ignore ATTRIBUTE_UNUSED) -{ - long val; - - if (get_absolute_expression_and_terminator (&val) != ',') - { - as_warn (_("Bad .mask directive")); - --input_line_pointer; - } - else - { - alpha_evax_proc->imask = val; - (void) get_absolute_expression (); - } - demand_empty_rest_of_line (); -} - -static void -s_alpha_fmask (int ignore ATTRIBUTE_UNUSED) -{ - long val; - - if (get_absolute_expression_and_terminator (&val) != ',') - { - as_warn (_("Bad .fmask directive")); - --input_line_pointer; - } - else - { - alpha_evax_proc->fmask = val; - (void) get_absolute_expression (); - } - demand_empty_rest_of_line (); -} - -static void -s_alpha_end (int ignore ATTRIBUTE_UNUSED) -{ - char c; - - c = get_symbol_end (); - *input_line_pointer = c; - demand_empty_rest_of_line (); - alpha_evax_proc = NULL; -} - -static void -s_alpha_file (int ignore ATTRIBUTE_UNUSED) -{ - symbolS *s; - int length; - static char case_hack[32]; - - sprintf (case_hack, "<CASE:%01d%01d>", - alpha_flag_hash_long_names, alpha_flag_show_after_trunc); - - s = symbol_find_or_make (case_hack); - symbol_get_bfdsym (s)->flags |= BSF_FILE; - - get_absolute_expression (); - s = symbol_find_or_make (demand_copy_string (&length)); - symbol_get_bfdsym (s)->flags |= BSF_FILE; - demand_empty_rest_of_line (); -} -#endif /* OBJ_EVAX */ - -/* Handle the .gprel32 pseudo op. */ - -static void -s_alpha_gprel32 (int ignore ATTRIBUTE_UNUSED) -{ - expressionS e; - char *p; - - SKIP_WHITESPACE (); - expression (&e); - -#ifdef OBJ_ELF - switch (e.X_op) - { - case O_constant: - e.X_add_symbol = section_symbol (absolute_section); - e.X_op = O_symbol; - /* FALLTHRU */ - case O_symbol: - break; - default: - abort (); - } -#else -#ifdef OBJ_ECOFF - switch (e.X_op) - { - case O_constant: - e.X_add_symbol = section_symbol (absolute_section); - /* fall through */ - case O_symbol: - e.X_op = O_subtract; - e.X_op_symbol = alpha_gp_symbol; - break; - default: - abort (); - } -#endif -#endif - - if (alpha_auto_align_on && alpha_current_align < 2) - alpha_align (2, (char *) NULL, alpha_insn_label, 0); - if (alpha_current_align > 2) - alpha_current_align = 2; - alpha_insn_label = NULL; - - p = frag_more (4); - memset (p, 0, 4); - fix_new_exp (frag_now, p - frag_now->fr_literal, 4, - &e, 0, BFD_RELOC_GPREL32); -} - -/* Handle floating point allocation pseudo-ops. This is like the - generic vresion, but it makes sure the current label, if any, is - correctly aligned. */ - -static void -s_alpha_float_cons (int type) -{ - int log_size; - - switch (type) - { - default: - case 'f': - case 'F': - log_size = 2; - break; - - case 'd': - case 'D': - case 'G': - log_size = 3; - break; - - case 'x': - case 'X': - case 'p': - case 'P': - log_size = 4; - break; - } - - if (alpha_auto_align_on && alpha_current_align < log_size) - alpha_align (log_size, (char *) NULL, alpha_insn_label, 0); - if (alpha_current_align > log_size) - alpha_current_align = log_size; - alpha_insn_label = NULL; - - float_cons (type); -} - -/* Handle the .proc pseudo op. We don't really do much with it except - parse it. */ - -static void -s_alpha_proc (int is_static ATTRIBUTE_UNUSED) -{ - char *name; - char c; - char *p; - symbolS *symbolP; - int temp; - - /* Takes ".proc name,nargs". */ - SKIP_WHITESPACE (); - name = input_line_pointer; - c = get_symbol_end (); - p = input_line_pointer; - symbolP = symbol_find_or_make (name); - *p = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - *p = 0; - as_warn (_("Expected comma after name \"%s\""), name); - *p = c; - temp = 0; - ignore_rest_of_line (); - } - else - { - input_line_pointer++; - temp = get_absolute_expression (); - } - /* *symbol_get_obj (symbolP) = (signed char) temp; */ - (void) symbolP; - as_warn (_("unhandled: .proc %s,%d"), name, temp); - demand_empty_rest_of_line (); -} - -/* Handle the .set pseudo op. This is used to turn on and off most of - the assembler features. */ - -static void -s_alpha_set (int x ATTRIBUTE_UNUSED) -{ - char *name, ch, *s; - int yesno = 1; - - SKIP_WHITESPACE (); - name = input_line_pointer; - ch = get_symbol_end (); - - s = name; - if (s[0] == 'n' && s[1] == 'o') - { - yesno = 0; - s += 2; - } - if (!strcmp ("reorder", s)) - /* ignore */ ; - else if (!strcmp ("at", s)) - alpha_noat_on = !yesno; - else if (!strcmp ("macro", s)) - alpha_macros_on = yesno; - else if (!strcmp ("move", s)) - /* ignore */ ; - else if (!strcmp ("volatile", s)) - /* ignore */ ; - else - as_warn (_("Tried to .set unrecognized mode `%s'"), name); - - *input_line_pointer = ch; - demand_empty_rest_of_line (); -} - -/* Handle the .base pseudo op. This changes the assembler's notion of - the $gp register. */ - -static void -s_alpha_base (int ignore ATTRIBUTE_UNUSED) -{ - SKIP_WHITESPACE (); - - if (*input_line_pointer == '$') - { - /* $rNN form. */ - input_line_pointer++; - if (*input_line_pointer == 'r') - input_line_pointer++; - } - - alpha_gp_register = get_absolute_expression (); - if (alpha_gp_register < 0 || alpha_gp_register > 31) - { - alpha_gp_register = AXP_REG_GP; - as_warn (_("Bad base register, using $%d."), alpha_gp_register); - } - - demand_empty_rest_of_line (); -} - -/* Handle the .align pseudo-op. This aligns to a power of two. It - also adjusts any current instruction label. We treat this the same - way the MIPS port does: .align 0 turns off auto alignment. */ - -static void -s_alpha_align (int ignore ATTRIBUTE_UNUSED) -{ - int align; - char fill, *pfill; - long max_alignment = 16; - - align = get_absolute_expression (); - if (align > max_alignment) - { - align = max_alignment; - as_bad (_("Alignment too large: %d. assumed"), align); - } - else if (align < 0) - { - as_warn (_("Alignment negative: 0 assumed")); - align = 0; - } - - if (*input_line_pointer == ',') - { - input_line_pointer++; - fill = get_absolute_expression (); - pfill = &fill; - } - else - pfill = NULL; - - if (align != 0) - { - alpha_auto_align_on = 1; - alpha_align (align, pfill, NULL, 1); - } - else - { - alpha_auto_align_on = 0; - } - alpha_insn_label = NULL; - - demand_empty_rest_of_line (); -} - -/* Hook the normal string processor to reset known alignment. */ - -static void -s_alpha_stringer (int terminate) -{ - alpha_current_align = 0; - alpha_insn_label = NULL; - stringer (8 + terminate); -} - -/* Hook the normal space processing to reset known alignment. */ - -static void -s_alpha_space (int ignore) -{ - alpha_current_align = 0; - alpha_insn_label = NULL; - s_space (ignore); -} - -/* Hook into cons for auto-alignment. */ - -void -alpha_cons_align (int size) -{ - int log_size; - - log_size = 0; - while ((size >>= 1) != 0) - ++log_size; - - if (alpha_auto_align_on && alpha_current_align < log_size) - alpha_align (log_size, (char *) NULL, alpha_insn_label, 0); - if (alpha_current_align > log_size) - alpha_current_align = log_size; - alpha_insn_label = NULL; -} - -/* Here come the .uword, .ulong, and .uquad explicitly unaligned - pseudos. We just turn off auto-alignment and call down to cons. */ - -static void -s_alpha_ucons (int bytes) -{ - int hold = alpha_auto_align_on; - alpha_auto_align_on = 0; - cons (bytes); - alpha_auto_align_on = hold; -} - -/* Switch the working cpu type. */ - -static void -s_alpha_arch (int ignored ATTRIBUTE_UNUSED) -{ - char *name, ch; - const struct cpu_type *p; - - SKIP_WHITESPACE (); - name = input_line_pointer; - ch = get_symbol_end (); - - for (p = cpu_types; p->name; ++p) - if (strcmp (name, p->name) == 0) - { - alpha_target_name = p->name, alpha_target = p->flags; - goto found; - } - as_warn (_("Unknown CPU identifier `%s'"), name); - -found: - *input_line_pointer = ch; - demand_empty_rest_of_line (); -} - -#ifdef DEBUG1 -/* print token expression with alpha specific extension. */ - -static void -alpha_print_token (FILE *f, const expressionS *exp) -{ - switch (exp->X_op) - { - case O_cpregister: - putc (',', f); - /* FALLTHRU */ - case O_pregister: - putc ('(', f); - { - expressionS nexp = *exp; - nexp.X_op = O_register; - print_expr_1 (f, &nexp); - } - putc (')', f); - break; - default: - print_expr_1 (f, exp); - break; - } -} -#endif - -/* The target specific pseudo-ops which we support. */ - -const pseudo_typeS md_pseudo_table[] = -{ -#ifdef OBJ_ECOFF - {"comm", s_alpha_comm, 0}, /* OSF1 compiler does this. */ - {"rdata", s_alpha_rdata, 0}, -#endif - {"text", s_alpha_text, 0}, - {"data", s_alpha_data, 0}, -#ifdef OBJ_ECOFF - {"sdata", s_alpha_sdata, 0}, -#endif -#ifdef OBJ_ELF - {"section", s_alpha_section, 0}, - {"section.s", s_alpha_section, 0}, - {"sect", s_alpha_section, 0}, - {"sect.s", s_alpha_section, 0}, -#endif -#ifdef OBJ_EVAX - {"section", s_alpha_section, 0}, - {"literals", s_alpha_literals, 0}, - {"pdesc", s_alpha_pdesc, 0}, - {"name", s_alpha_name, 0}, - {"linkage", s_alpha_linkage, 0}, - {"code_address", s_alpha_code_address, 0}, - {"ent", s_alpha_ent, 0}, - {"frame", s_alpha_frame, 0}, - {"fp_save", s_alpha_fp_save, 0}, - {"mask", s_alpha_mask, 0}, - {"fmask", s_alpha_fmask, 0}, - {"end", s_alpha_end, 0}, - {"file", s_alpha_file, 0}, - {"rdata", s_alpha_section, 1}, - {"comm", s_alpha_comm, 0}, - {"link", s_alpha_section, 3}, - {"ctors", s_alpha_section, 4}, - {"dtors", s_alpha_section, 5}, - {"handler", s_alpha_handler, 0}, - {"handler_data", s_alpha_handler, 1}, -#endif -#ifdef OBJ_ELF - /* Frame related pseudos. */ - {"ent", s_alpha_ent, 0}, - {"end", s_alpha_end, 0}, - {"mask", s_alpha_mask, 0}, - {"fmask", s_alpha_mask, 1}, - {"frame", s_alpha_frame, 0}, - {"prologue", s_alpha_prologue, 0}, - {"file", s_alpha_file, 5}, - {"loc", s_alpha_loc, 9}, - {"stabs", s_alpha_stab, 's'}, - {"stabn", s_alpha_stab, 'n'}, - {"usepv", s_alpha_usepv, 0}, - /* COFF debugging related pseudos. */ - {"begin", s_alpha_coff_wrapper, 0}, - {"bend", s_alpha_coff_wrapper, 1}, - {"def", s_alpha_coff_wrapper, 2}, - {"dim", s_alpha_coff_wrapper, 3}, - {"endef", s_alpha_coff_wrapper, 4}, - {"scl", s_alpha_coff_wrapper, 5}, - {"tag", s_alpha_coff_wrapper, 6}, - {"val", s_alpha_coff_wrapper, 7}, -#else -#ifdef OBJ_EVAX - {"prologue", s_alpha_prologue, 0}, -#else - {"prologue", s_ignore, 0}, -#endif -#endif - {"gprel32", s_alpha_gprel32, 0}, - {"t_floating", s_alpha_float_cons, 'd'}, - {"s_floating", s_alpha_float_cons, 'f'}, - {"f_floating", s_alpha_float_cons, 'F'}, - {"g_floating", s_alpha_float_cons, 'G'}, - {"d_floating", s_alpha_float_cons, 'D'}, - - {"proc", s_alpha_proc, 0}, - {"aproc", s_alpha_proc, 1}, - {"set", s_alpha_set, 0}, - {"reguse", s_ignore, 0}, - {"livereg", s_ignore, 0}, - {"base", s_alpha_base, 0}, /*??*/ - {"option", s_ignore, 0}, - {"aent", s_ignore, 0}, - {"ugen", s_ignore, 0}, - {"eflag", s_ignore, 0}, - - {"align", s_alpha_align, 0}, - {"double", s_alpha_float_cons, 'd'}, - {"float", s_alpha_float_cons, 'f'}, - {"single", s_alpha_float_cons, 'f'}, - {"ascii", s_alpha_stringer, 0}, - {"asciz", s_alpha_stringer, 1}, - {"string", s_alpha_stringer, 1}, - {"space", s_alpha_space, 0}, - {"skip", s_alpha_space, 0}, - {"zero", s_alpha_space, 0}, - -/* Unaligned data pseudos. */ - {"uword", s_alpha_ucons, 2}, - {"ulong", s_alpha_ucons, 4}, - {"uquad", s_alpha_ucons, 8}, - -#ifdef OBJ_ELF -/* Dwarf wants these versions of unaligned. */ - {"2byte", s_alpha_ucons, 2}, - {"4byte", s_alpha_ucons, 4}, - {"8byte", s_alpha_ucons, 8}, -#endif - -/* We don't do any optimizing, so we can safely ignore these. */ - {"noalias", s_ignore, 0}, - {"alias", s_ignore, 0}, - - {"arch", s_alpha_arch, 0}, - - {NULL, 0, 0}, -}; - -#ifdef OBJ_ECOFF - -/* @@@ GP selection voodoo. All of this seems overly complicated and - unnecessary; which is the primary reason it's for ECOFF only. */ - -static inline void -maybe_set_gp (asection *sec) -{ - bfd_vma vma; - - if (!sec) - return; - vma = bfd_get_section_vma (sec->owner, sec); - if (vma && vma < alpha_gp_value) - alpha_gp_value = vma; -} - -static void -select_gp_value (void) -{ - gas_assert (alpha_gp_value == 0); - - /* Get minus-one in whatever width... */ - alpha_gp_value = 0; - alpha_gp_value--; - - /* Select the smallest VMA of these existing sections. */ - maybe_set_gp (alpha_lita_section); - -/* @@ Will a simple 0x8000 work here? If not, why not? */ -#define GP_ADJUSTMENT (0x8000 - 0x10) - - alpha_gp_value += GP_ADJUSTMENT; - - S_SET_VALUE (alpha_gp_symbol, alpha_gp_value); - -#ifdef DEBUG1 - printf (_("Chose GP value of %lx\n"), alpha_gp_value); -#endif -} -#endif /* OBJ_ECOFF */ - -#ifdef OBJ_ELF -/* Map 's' to SHF_ALPHA_GPREL. */ - -bfd_vma -alpha_elf_section_letter (int letter, char **ptr_msg) -{ - if (letter == 's') - return SHF_ALPHA_GPREL; - - *ptr_msg = _("bad .section directive: want a,s,w,x,M,S,G,T in string"); - return -1; -} - -/* Map SHF_ALPHA_GPREL to SEC_SMALL_DATA. */ - -flagword -alpha_elf_section_flags (flagword flags, bfd_vma attr, int type ATTRIBUTE_UNUSED) -{ - if (attr & SHF_ALPHA_GPREL) - flags |= SEC_SMALL_DATA; - return flags; -} -#endif /* OBJ_ELF */ - -/* This is called from HANDLE_ALIGN in write.c. Fill in the contents - of an rs_align_code fragment. */ - -void -alpha_handle_align (fragS *fragp) -{ - static char const unop[4] = { 0x00, 0x00, 0xfe, 0x2f }; - static char const nopunop[8] = - { - 0x1f, 0x04, 0xff, 0x47, - 0x00, 0x00, 0xfe, 0x2f - }; - - int bytes, fix; - char *p; - - if (fragp->fr_type != rs_align_code) - return; - - bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix; - p = fragp->fr_literal + fragp->fr_fix; - fix = 0; - - if (bytes & 3) - { - fix = bytes & 3; - memset (p, 0, fix); - p += fix; - bytes -= fix; - } - - if (bytes & 4) - { - memcpy (p, unop, 4); - p += 4; - bytes -= 4; - fix += 4; - } - - memcpy (p, nopunop, 8); - - fragp->fr_fix += fix; - fragp->fr_var = 8; -} - -/* Public interface functions. */ - -/* This function is called once, at assembler startup time. It sets - up all the tables, etc. that the MD part of the assembler will - need, that can be determined before arguments are parsed. */ - -void -md_begin (void) -{ - unsigned int i; - - /* Verify that X_op field is wide enough. */ - { - expressionS e; - - e.X_op = O_max; - gas_assert (e.X_op == O_max); - } - - /* Create the opcode hash table. */ - alpha_opcode_hash = hash_new (); - - for (i = 0; i < alpha_num_opcodes;) - { - const char *name, *retval, *slash; - - name = alpha_opcodes[i].name; - retval = hash_insert (alpha_opcode_hash, name, (void *) &alpha_opcodes[i]); - if (retval) - as_fatal (_("internal error: can't hash opcode `%s': %s"), - name, retval); - - /* Some opcodes include modifiers of various sorts with a "/mod" - syntax, like the architecture manual suggests. However, for - use with gcc at least, we also need access to those same opcodes - without the "/". */ - - if ((slash = strchr (name, '/')) != NULL) - { - char *p = (char *) xmalloc (strlen (name)); - - memcpy (p, name, slash - name); - strcpy (p + (slash - name), slash + 1); - - (void) hash_insert (alpha_opcode_hash, p, (void *) &alpha_opcodes[i]); - /* Ignore failures -- the opcode table does duplicate some - variants in different forms, like "hw_stq" and "hw_st/q". */ - } - - while (++i < alpha_num_opcodes - && (alpha_opcodes[i].name == name - || !strcmp (alpha_opcodes[i].name, name))) - continue; - } - - /* Create the macro hash table. */ - alpha_macro_hash = hash_new (); - - for (i = 0; i < alpha_num_macros;) - { - const char *name, *retval; - - name = alpha_macros[i].name; - retval = hash_insert (alpha_macro_hash, name, (void *) &alpha_macros[i]); - if (retval) - as_fatal (_("internal error: can't hash macro `%s': %s"), - name, retval); - - while (++i < alpha_num_macros - && (alpha_macros[i].name == name - || !strcmp (alpha_macros[i].name, name))) - continue; - } - - /* Construct symbols for each of the registers. */ - for (i = 0; i < 32; ++i) - { - char name[4]; - - sprintf (name, "$%d", i); - alpha_register_table[i] = symbol_create (name, reg_section, i, - &zero_address_frag); - } - - for (; i < 64; ++i) - { - char name[5]; - - sprintf (name, "$f%d", i - 32); - alpha_register_table[i] = symbol_create (name, reg_section, i, - &zero_address_frag); - } - - /* Create the special symbols and sections we'll be using. */ - - /* So .sbss will get used for tiny objects. */ - bfd_set_gp_size (stdoutput, g_switch_value); - -#ifdef OBJ_ECOFF - create_literal_section (".lita", &alpha_lita_section, &alpha_lita_symbol); - - /* For handling the GP, create a symbol that won't be output in the - symbol table. We'll edit it out of relocs later. */ - alpha_gp_symbol = symbol_create ("<GP value>", alpha_lita_section, 0x8000, - &zero_address_frag); -#endif - -#ifdef OBJ_EVAX - create_literal_section (".link", &alpha_link_section, &alpha_link_symbol); -#endif - -#ifdef OBJ_ELF - if (ECOFF_DEBUGGING) - { - segT sec = subseg_new (".mdebug", (subsegT) 0); - bfd_set_section_flags (stdoutput, sec, SEC_HAS_CONTENTS | SEC_READONLY); - bfd_set_section_alignment (stdoutput, sec, 3); - } -#endif - - /* Create literal lookup hash table. */ - alpha_literal_hash = hash_new (); - - subseg_set (text_section, 0); -} - -/* The public interface to the instruction assembler. */ - -void -md_assemble (char *str) -{ - /* Current maximum is 13. */ - char opname[32]; - expressionS tok[MAX_INSN_ARGS]; - int ntok, trunclen; - size_t opnamelen; - - /* Split off the opcode. */ - opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_/46819"); - trunclen = (opnamelen < sizeof (opname) - 1 - ? opnamelen - : sizeof (opname) - 1); - memcpy (opname, str, trunclen); - opname[trunclen] = '\0'; - - /* Tokenize the rest of the line. */ - if ((ntok = tokenize_arguments (str + opnamelen, tok, MAX_INSN_ARGS)) < 0) - { - if (ntok != TOKENIZE_ERROR_REPORT) - as_bad (_("syntax error")); - - return; - } - - /* Finish it off. */ - assemble_tokens (opname, tok, ntok, alpha_macros_on); -} - -/* Round up a section's size to the appropriate boundary. */ - -valueT -md_section_align (segT seg, valueT size) -{ - int align = bfd_get_section_alignment (stdoutput, seg); - valueT mask = ((valueT) 1 << align) - 1; - - return (size + mask) & ~mask; -} - -/* Turn a string in input_line_pointer into a floating point constant - of type TYPE, and store the appropriate bytes in *LITP. The number - of LITTLENUMS emitted is stored in *SIZEP. An error message is - returned, or NULL on OK. */ - -char * -md_atof (int type, char *litP, int *sizeP) -{ - extern char *vax_md_atof (int, char *, int *); - - switch (type) - { - /* VAX floats. */ - case 'G': - /* vax_md_atof() doesn't like "G" for some reason. */ - type = 'g'; - case 'F': - case 'D': - return vax_md_atof (type, litP, sizeP); - - default: - return ieee_md_atof (type, litP, sizeP, FALSE); - } -} - -/* Take care of the target-specific command-line options. */ - -int -md_parse_option (int c, char *arg) -{ - switch (c) - { - case 'F': - alpha_nofloats_on = 1; - break; - - case OPTION_32ADDR: - alpha_addr32_on = 1; - break; - - case 'g': - alpha_debug = 1; - break; - - case 'G': - g_switch_value = atoi (arg); - break; - - case 'm': - { - const struct cpu_type *p; - - for (p = cpu_types; p->name; ++p) - if (strcmp (arg, p->name) == 0) - { - alpha_target_name = p->name, alpha_target = p->flags; - goto found; - } - as_warn (_("Unknown CPU identifier `%s'"), arg); - found:; - } - break; - -#ifdef OBJ_EVAX - case '+': /* For g++. Hash any name > 63 chars long. */ - alpha_flag_hash_long_names = 1; - break; - - case 'H': /* Show new symbol after hash truncation. */ - alpha_flag_show_after_trunc = 1; - break; - - case 'h': /* For gnu-c/vax compatibility. */ - break; - - case OPTION_REPLACE: - alpha_flag_replace = 1; - break; - - case OPTION_NOREPLACE: - alpha_flag_replace = 0; - break; -#endif - - case OPTION_RELAX: - alpha_flag_relax = 1; - break; - -#ifdef OBJ_ELF - case OPTION_MDEBUG: - alpha_flag_mdebug = 1; - break; - case OPTION_NO_MDEBUG: - alpha_flag_mdebug = 0; - break; -#endif - - default: - return 0; - } - - return 1; -} - -/* Print a description of the command-line options that we accept. */ - -void -md_show_usage (FILE *stream) -{ - fputs (_("\ -Alpha options:\n\ --32addr treat addresses as 32-bit values\n\ --F lack floating point instructions support\n\ --mev4 | -mev45 | -mev5 | -mev56 | -mpca56 | -mev6 | -mev67 | -mev68 | -mall\n\ - specify variant of Alpha architecture\n\ --m21064 | -m21066 | -m21164 | -m21164a | -m21164pc | -m21264 | -m21264a | -m21264b\n\ - these variants include PALcode opcodes\n"), - stream); -#ifdef OBJ_EVAX - fputs (_("\ -VMS options:\n\ --+ encode (don't truncate) names longer than 64 characters\n\ --H show new symbol after hash truncation\n\ --replace/-noreplace enable or disable the optimization of procedure calls\n"), - stream); -#endif -} - -/* Decide from what point a pc-relative relocation is relative to, - relative to the pc-relative fixup. Er, relatively speaking. */ - -long -md_pcrel_from (fixS *fixP) -{ - valueT addr = fixP->fx_where + fixP->fx_frag->fr_address; - - switch (fixP->fx_r_type) - { - case BFD_RELOC_23_PCREL_S2: - case BFD_RELOC_ALPHA_HINT: - case BFD_RELOC_ALPHA_BRSGP: - return addr + 4; - default: - return addr; - } -} - -/* Attempt to simplify or even eliminate a fixup. The return value is - ignored; perhaps it was once meaningful, but now it is historical. - To indicate that a fixup has been eliminated, set fixP->fx_done. - - For ELF, here it is that we transform the GPDISP_HI16 reloc we used - internally into the GPDISP reloc used externally. We had to do - this so that we'd have the GPDISP_LO16 reloc as a tag to compute - the distance to the "lda" instruction for setting the addend to - GPDISP. */ - -void -md_apply_fix (fixS *fixP, valueT * valP, segT seg) -{ - char * const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where; - valueT value = * valP; - unsigned image, size; - - switch (fixP->fx_r_type) - { - /* The GPDISP relocations are processed internally with a symbol - referring to the current function's section; we need to drop - in a value which, when added to the address of the start of - the function, gives the desired GP. */ - case BFD_RELOC_ALPHA_GPDISP_HI16: - { - fixS *next = fixP->fx_next; - - /* With user-specified !gpdisp relocations, we can be missing - the matching LO16 reloc. We will have already issued an - error message. */ - if (next) - fixP->fx_offset = (next->fx_frag->fr_address + next->fx_where - - fixP->fx_frag->fr_address - fixP->fx_where); - - value = (value - sign_extend_16 (value)) >> 16; - } -#ifdef OBJ_ELF - fixP->fx_r_type = BFD_RELOC_ALPHA_GPDISP; -#endif - goto do_reloc_gp; - - case BFD_RELOC_ALPHA_GPDISP_LO16: - value = sign_extend_16 (value); - fixP->fx_offset = 0; -#ifdef OBJ_ELF - fixP->fx_done = 1; -#endif - - do_reloc_gp: - fixP->fx_addsy = section_symbol (seg); - md_number_to_chars (fixpos, value, 2); - break; - - case BFD_RELOC_16: - if (fixP->fx_pcrel) - fixP->fx_r_type = BFD_RELOC_16_PCREL; - size = 2; - goto do_reloc_xx; - - case BFD_RELOC_32: - if (fixP->fx_pcrel) - fixP->fx_r_type = BFD_RELOC_32_PCREL; - size = 4; - goto do_reloc_xx; - - case BFD_RELOC_64: - if (fixP->fx_pcrel) - fixP->fx_r_type = BFD_RELOC_64_PCREL; - size = 8; - - do_reloc_xx: - if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0) - { - md_number_to_chars (fixpos, value, size); - goto done; - } - return; - -#ifdef OBJ_ECOFF - case BFD_RELOC_GPREL32: - gas_assert (fixP->fx_subsy == alpha_gp_symbol); - fixP->fx_subsy = 0; - /* FIXME: inherited this obliviousness of `value' -- why? */ - md_number_to_chars (fixpos, -alpha_gp_value, 4); - break; -#else - case BFD_RELOC_GPREL32: -#endif - case BFD_RELOC_GPREL16: - case BFD_RELOC_ALPHA_GPREL_HI16: - case BFD_RELOC_ALPHA_GPREL_LO16: - return; - - case BFD_RELOC_23_PCREL_S2: - if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0) - { - image = bfd_getl32 (fixpos); - image = (image & ~0x1FFFFF) | ((value >> 2) & 0x1FFFFF); - goto write_done; - } - return; - - case BFD_RELOC_ALPHA_HINT: - if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0) - { - image = bfd_getl32 (fixpos); - image = (image & ~0x3FFF) | ((value >> 2) & 0x3FFF); - goto write_done; - } - return; - -#ifdef OBJ_ELF - case BFD_RELOC_ALPHA_BRSGP: - return; - - case BFD_RELOC_ALPHA_TLSGD: - case BFD_RELOC_ALPHA_TLSLDM: - case BFD_RELOC_ALPHA_GOTDTPREL16: - case BFD_RELOC_ALPHA_DTPREL_HI16: - case BFD_RELOC_ALPHA_DTPREL_LO16: - case BFD_RELOC_ALPHA_DTPREL16: - case BFD_RELOC_ALPHA_GOTTPREL16: - case BFD_RELOC_ALPHA_TPREL_HI16: - case BFD_RELOC_ALPHA_TPREL_LO16: - case BFD_RELOC_ALPHA_TPREL16: - if (fixP->fx_addsy) - S_SET_THREAD_LOCAL (fixP->fx_addsy); - return; -#endif - -#ifdef OBJ_ECOFF - case BFD_RELOC_ALPHA_LITERAL: - md_number_to_chars (fixpos, value, 2); - return; -#endif - case BFD_RELOC_ALPHA_ELF_LITERAL: - case BFD_RELOC_ALPHA_LITUSE: - case BFD_RELOC_ALPHA_LINKAGE: - case BFD_RELOC_ALPHA_CODEADDR: - return; - -#ifdef OBJ_EVAX - case BFD_RELOC_ALPHA_NOP: - value -= (8 + 4); /* PC-relative, base is jsr+4. */ - - /* From B.4.5.2 of the OpenVMS Linker Utility Manual: - "Finally, the ETIR$C_STC_BSR command passes the same address - as ETIR$C_STC_NOP (so that they will fail or succeed together), - and the same test is done again." */ - if (S_GET_SEGMENT (fixP->fx_addsy) == undefined_section) - { - fixP->fx_addnumber = -value; - return; - } - - if ((abs (value) >> 2) & ~0xfffff) - goto done; - else - { - /* Change to a nop. */ - image = 0x47FF041F; - goto write_done; - } - - case BFD_RELOC_ALPHA_LDA: - /* fixup_segment sets fixP->fx_addsy to NULL when it can pre-compute - the value for an O_subtract. */ - if (fixP->fx_addsy - && S_GET_SEGMENT (fixP->fx_addsy) == undefined_section) - { - fixP->fx_addnumber = symbol_get_bfdsym (fixP->fx_subsy)->value; - return; - } - - if ((abs (value)) & ~0x7fff) - goto done; - else - { - /* Change to an lda. */ - image = 0x237B0000 | (value & 0xFFFF); - goto write_done; - } - - case BFD_RELOC_ALPHA_BSR: - case BFD_RELOC_ALPHA_BOH: - value -= 4; /* PC-relative, base is jsr+4. */ - - /* See comment in the BFD_RELOC_ALPHA_NOP case above. */ - if (S_GET_SEGMENT (fixP->fx_addsy) == undefined_section) - { - fixP->fx_addnumber = -value; - return; - } - - if ((abs (value) >> 2) & ~0xfffff) - { - /* Out of range. */ - if (fixP->fx_r_type == BFD_RELOC_ALPHA_BOH) - { - /* Add a hint. */ - image = bfd_getl32(fixpos); - image = (image & ~0x3FFF) | ((value >> 2) & 0x3FFF); - goto write_done; - } - goto done; - } - else - { - /* Change to a branch. */ - image = 0xD3400000 | ((value >> 2) & 0x1FFFFF); - goto write_done; - } -#endif - - case BFD_RELOC_VTABLE_INHERIT: - case BFD_RELOC_VTABLE_ENTRY: - return; - - default: - { - const struct alpha_operand *operand; - - if ((int) fixP->fx_r_type >= 0) - as_fatal (_("unhandled relocation type %s"), - bfd_get_reloc_code_name (fixP->fx_r_type)); - - gas_assert (-(int) fixP->fx_r_type < (int) alpha_num_operands); - operand = &alpha_operands[-(int) fixP->fx_r_type]; - - /* The rest of these fixups only exist internally during symbol - resolution and have no representation in the object file. - Therefore they must be completely resolved as constants. */ - - if (fixP->fx_addsy != 0 - && S_GET_SEGMENT (fixP->fx_addsy) != absolute_section) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("non-absolute expression in constant field")); - - image = bfd_getl32 (fixpos); - image = insert_operand (image, operand, (offsetT) value, - fixP->fx_file, fixP->fx_line); - } - goto write_done; - } - - if (fixP->fx_addsy != 0 || fixP->fx_pcrel != 0) - return; - else - { - as_warn_where (fixP->fx_file, fixP->fx_line, - _("type %d reloc done?\n"), (int) fixP->fx_r_type); - goto done; - } - -write_done: - md_number_to_chars (fixpos, image, 4); - -done: - fixP->fx_done = 1; -} - -/* Look for a register name in the given symbol. */ - -symbolS * -md_undefined_symbol (char *name) -{ - if (*name == '$') - { - int is_float = 0, num; - - switch (*++name) - { - case 'f': - if (name[1] == 'p' && name[2] == '\0') - return alpha_register_table[AXP_REG_FP]; - is_float = 32; - /* Fall through. */ - - case 'r': - if (!ISDIGIT (*++name)) - break; - /* Fall through. */ - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - if (name[1] == '\0') - num = name[0] - '0'; - else if (name[0] != '0' && ISDIGIT (name[1]) && name[2] == '\0') - { - num = (name[0] - '0') * 10 + name[1] - '0'; - if (num >= 32) - break; - } - else - break; - - if (!alpha_noat_on && (num + is_float) == AXP_REG_AT) - as_warn (_("Used $at without \".set noat\"")); - return alpha_register_table[num + is_float]; - - case 'a': - if (name[1] == 't' && name[2] == '\0') - { - if (!alpha_noat_on) - as_warn (_("Used $at without \".set noat\"")); - return alpha_register_table[AXP_REG_AT]; - } - break; - - case 'g': - if (name[1] == 'p' && name[2] == '\0') - return alpha_register_table[alpha_gp_register]; - break; - - case 's': - if (name[1] == 'p' && name[2] == '\0') - return alpha_register_table[AXP_REG_SP]; - break; - } - } - return NULL; -} - -#ifdef OBJ_ECOFF -/* @@@ Magic ECOFF bits. */ - -void -alpha_frob_ecoff_data (void) -{ - select_gp_value (); - /* $zero and $f31 are read-only. */ - alpha_gprmask &= ~1; - alpha_fprmask &= ~1; -} -#endif - -/* Hook to remember a recently defined label so that the auto-align - code can adjust the symbol after we know what alignment will be - required. */ - -void -alpha_define_label (symbolS *sym) -{ - alpha_insn_label = sym; -#ifdef OBJ_ELF - dwarf2_emit_label (sym); -#endif -} - -/* Return true if we must always emit a reloc for a type and false if - there is some hope of resolving it at assembly time. */ - -int -alpha_force_relocation (fixS *f) -{ - if (alpha_flag_relax) - return 1; - - switch (f->fx_r_type) - { - case BFD_RELOC_ALPHA_GPDISP_HI16: - case BFD_RELOC_ALPHA_GPDISP_LO16: - case BFD_RELOC_ALPHA_GPDISP: - case BFD_RELOC_ALPHA_LITERAL: - case BFD_RELOC_ALPHA_ELF_LITERAL: - case BFD_RELOC_ALPHA_LITUSE: - case BFD_RELOC_GPREL16: - case BFD_RELOC_GPREL32: - case BFD_RELOC_ALPHA_GPREL_HI16: - case BFD_RELOC_ALPHA_GPREL_LO16: - case BFD_RELOC_ALPHA_LINKAGE: - case BFD_RELOC_ALPHA_CODEADDR: - case BFD_RELOC_ALPHA_BRSGP: - case BFD_RELOC_ALPHA_TLSGD: - case BFD_RELOC_ALPHA_TLSLDM: - case BFD_RELOC_ALPHA_GOTDTPREL16: - case BFD_RELOC_ALPHA_DTPREL_HI16: - case BFD_RELOC_ALPHA_DTPREL_LO16: - case BFD_RELOC_ALPHA_DTPREL16: - case BFD_RELOC_ALPHA_GOTTPREL16: - case BFD_RELOC_ALPHA_TPREL_HI16: - case BFD_RELOC_ALPHA_TPREL_LO16: - case BFD_RELOC_ALPHA_TPREL16: -#ifdef OBJ_EVAX - case BFD_RELOC_ALPHA_NOP: - case BFD_RELOC_ALPHA_BSR: - case BFD_RELOC_ALPHA_LDA: - case BFD_RELOC_ALPHA_BOH: -#endif - return 1; - - default: - break; - } - - return generic_force_reloc (f); -} - -/* Return true if we can partially resolve a relocation now. */ - -int -alpha_fix_adjustable (fixS *f) -{ - /* Are there any relocation types for which we must generate a - reloc but we can adjust the values contained within it? */ - switch (f->fx_r_type) - { - case BFD_RELOC_ALPHA_GPDISP_HI16: - case BFD_RELOC_ALPHA_GPDISP_LO16: - case BFD_RELOC_ALPHA_GPDISP: - return 0; - - case BFD_RELOC_ALPHA_LITERAL: - case BFD_RELOC_ALPHA_ELF_LITERAL: - case BFD_RELOC_ALPHA_LITUSE: - case BFD_RELOC_ALPHA_LINKAGE: - case BFD_RELOC_ALPHA_CODEADDR: - return 1; - - case BFD_RELOC_VTABLE_ENTRY: - case BFD_RELOC_VTABLE_INHERIT: - return 0; - - case BFD_RELOC_GPREL16: - case BFD_RELOC_GPREL32: - case BFD_RELOC_ALPHA_GPREL_HI16: - case BFD_RELOC_ALPHA_GPREL_LO16: - case BFD_RELOC_23_PCREL_S2: - case BFD_RELOC_16: - case BFD_RELOC_32: - case BFD_RELOC_64: - case BFD_RELOC_ALPHA_HINT: - return 1; - - case BFD_RELOC_ALPHA_TLSGD: - case BFD_RELOC_ALPHA_TLSLDM: - case BFD_RELOC_ALPHA_GOTDTPREL16: - case BFD_RELOC_ALPHA_DTPREL_HI16: - case BFD_RELOC_ALPHA_DTPREL_LO16: - case BFD_RELOC_ALPHA_DTPREL16: - case BFD_RELOC_ALPHA_GOTTPREL16: - case BFD_RELOC_ALPHA_TPREL_HI16: - case BFD_RELOC_ALPHA_TPREL_LO16: - case BFD_RELOC_ALPHA_TPREL16: - /* ??? No idea why we can't return a reference to .tbss+10, but - we're preventing this in the other assemblers. Follow for now. */ - return 0; - -#ifdef OBJ_ELF - case BFD_RELOC_ALPHA_BRSGP: - /* If we have a BRSGP reloc to a local symbol, adjust it to BRADDR and - let it get resolved at assembly time. */ - { - symbolS *sym = f->fx_addsy; - const char *name; - int offset = 0; - - if (generic_force_reloc (f)) - return 0; - - switch (S_GET_OTHER (sym) & STO_ALPHA_STD_GPLOAD) - { - case STO_ALPHA_NOPV: - break; - case STO_ALPHA_STD_GPLOAD: - offset = 8; - break; - default: - if (S_IS_LOCAL (sym)) - name = "<local>"; - else - name = S_GET_NAME (sym); - as_bad_where (f->fx_file, f->fx_line, - _("!samegp reloc against symbol without .prologue: %s"), - name); - break; - } - f->fx_r_type = BFD_RELOC_23_PCREL_S2; - f->fx_offset += offset; - return 1; - } -#endif -#ifdef OBJ_EVAX - case BFD_RELOC_ALPHA_NOP: - case BFD_RELOC_ALPHA_BSR: - case BFD_RELOC_ALPHA_LDA: - case BFD_RELOC_ALPHA_BOH: - return 1; -#endif - - default: - return 1; - } -} - -/* Generate the BFD reloc to be stuck in the object file from the - fixup used internally in the assembler. */ - -arelent * -tc_gen_reloc (asection *sec ATTRIBUTE_UNUSED, - fixS *fixp) -{ - arelent *reloc; - - reloc = (arelent *) xmalloc (sizeof (* reloc)); - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - - /* Make sure none of our internal relocations make it this far. - They'd better have been fully resolved by this point. */ - gas_assert ((int) fixp->fx_r_type > 0); - - reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); - if (reloc->howto == NULL) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("cannot represent `%s' relocation in object file"), - bfd_get_reloc_code_name (fixp->fx_r_type)); - return NULL; - } - - if (!fixp->fx_pcrel != !reloc->howto->pc_relative) - as_fatal (_("internal error? cannot generate `%s' relocation"), - bfd_get_reloc_code_name (fixp->fx_r_type)); - - gas_assert (!fixp->fx_pcrel == !reloc->howto->pc_relative); - - reloc->addend = fixp->fx_offset; - -#ifdef OBJ_ECOFF - /* Fake out bfd_perform_relocation. sigh. */ - /* ??? Better would be to use the special_function hook. */ - if (fixp->fx_r_type == BFD_RELOC_ALPHA_LITERAL) - reloc->addend = -alpha_gp_value; -#endif - -#ifdef OBJ_EVAX - switch (fixp->fx_r_type) - { - struct evax_private_udata_struct *udata; - const char *pname; - int pname_len; - - case BFD_RELOC_ALPHA_LINKAGE: - /* Copy the linkage index. */ - reloc->addend = fixp->fx_addnumber; - break; - - case BFD_RELOC_ALPHA_NOP: - case BFD_RELOC_ALPHA_BSR: - case BFD_RELOC_ALPHA_LDA: - case BFD_RELOC_ALPHA_BOH: - pname = symbol_get_bfdsym (fixp->fx_addsy)->name; - - /* We need the non-suffixed name of the procedure. Beware that - the main symbol might be equated so look it up and take its name. */ - pname_len = strlen (pname); - if (pname_len > 4 && strcmp (pname + pname_len - 4, "..en") == 0) - { - symbolS *sym; - char *my_pname = (char *) alloca (pname_len - 4 + 1); - - memcpy (my_pname, pname, pname_len - 4); - my_pname [pname_len - 4] = 0; - sym = symbol_find (my_pname); - if (sym == NULL) - abort (); - - while (symbol_equated_reloc_p (sym)) - { - symbolS *n = symbol_get_value_expression (sym)->X_add_symbol; - - /* We must avoid looping, as that can occur with a badly - written program. */ - if (n == sym) - break; - sym = n; - } - pname = symbol_get_bfdsym (sym)->name; - } - - udata = (struct evax_private_udata_struct *) - xmalloc (sizeof (struct evax_private_udata_struct)); - udata->enbsym = symbol_get_bfdsym (fixp->fx_addsy); - udata->bsym = symbol_get_bfdsym (fixp->tc_fix_data.info->psym); - udata->origname = (char *)pname; - udata->lkindex = ((struct evax_private_udata_struct *) - symbol_get_bfdsym (fixp->tc_fix_data.info->sym)->udata.p)->lkindex; - reloc->sym_ptr_ptr = (void *)udata; - reloc->addend = fixp->fx_addnumber; - - default: - break; - } -#endif - - return reloc; -} - -/* Parse a register name off of the input_line and return a register - number. Gets md_undefined_symbol above to do the register name - matching for us. - - Only called as a part of processing the ECOFF .frame directive. */ - -int -tc_get_register (int frame ATTRIBUTE_UNUSED) -{ - int framereg = AXP_REG_SP; - - SKIP_WHITESPACE (); - if (*input_line_pointer == '$') - { - char *s = input_line_pointer; - char c = get_symbol_end (); - symbolS *sym = md_undefined_symbol (s); - - *strchr (s, '\0') = c; - if (sym && (framereg = S_GET_VALUE (sym)) <= 31) - goto found; - } - as_warn (_("frame reg expected, using $%d."), framereg); - -found: - note_gpreg (framereg); - return framereg; -} - -/* This is called before the symbol table is processed. In order to - work with gcc when using mips-tfile, we must keep all local labels. - However, in other cases, we want to discard them. If we were - called with -g, but we didn't see any debugging information, it may - mean that gcc is smuggling debugging information through to - mips-tfile, in which case we must generate all local labels. */ - -#ifdef OBJ_ECOFF - -void -alpha_frob_file_before_adjust (void) -{ - if (alpha_debug != 0 - && ! ecoff_debugging_seen) - flag_keep_locals = 1; -} - -#endif /* OBJ_ECOFF */ - -/* The Alpha has support for some VAX floating point types, as well as for - IEEE floating point. We consider IEEE to be the primary floating point - format, and sneak in the VAX floating point support here. */ -#include "config/atof-vax.c" |