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