#include "as.h"
#include "subsegs.h"
#include "struc-symbol.h"
#include "ecoff.h"
#include "opcode/alpha.h"
#ifdef OBJ_ELF
#include "elf/alpha.h"
#include "dwarf2dbg.h"
#include "dw2gencfi.h"
#endif
#include "safe-ctype.h"
#define TOKENIZE_ERROR -1
#define TOKENIZE_ERROR_REPORT -2
#define MAX_INSN_FIXUPS 2
#define MAX_INSN_ARGS 5
struct alpha_fixup
{
expressionS exp;
bfd_reloc_code_real_type reloc;
};
struct alpha_insn
{
unsigned insn;
int nfixups;
struct alpha_fixup fixups[MAX_INSN_FIXUPS];
long sequence;
};
enum alpha_macro_arg
{
MACRO_EOA = 1,
MACRO_IR,
MACRO_PIR,
MACRO_OPIR,
MACRO_CPIR,
MACRO_FPR,
MACRO_EXP,
};
struct alpha_macro
{
const char *name;
void (*emit) PARAMS ((const expressionS *, int, const PTR));
const PTR arg;
enum alpha_macro_arg argsets[16];
};
#define O_pregister O_md1
#define O_cpregister O_md2
#define O_literal O_md3
#define O_lituse_addr O_md4
#define O_lituse_base O_md5
#define O_lituse_bytoff O_md6
#define O_lituse_jsr O_md7
#define O_lituse_tlsgd O_md8
#define O_lituse_tlsldm O_md9
#define O_gpdisp O_md10
#define O_gprelhigh O_md11
#define O_gprellow O_md12
#define O_gprel O_md13
#define O_samegp O_md14
#define O_tlsgd O_md15
#define O_tlsldm O_md16
#define O_gotdtprel O_md17
#define O_dtprelhi O_md18
#define O_dtprello O_md19
#define O_dtprel O_md20
#define O_gottprel O_md21
#define O_tprelhi O_md22
#define O_tprello O_md23
#define O_tprel O_md24
#define DUMMY_RELOC_LITUSE_ADDR (BFD_RELOC_UNUSED + 1)
#define DUMMY_RELOC_LITUSE_BASE (BFD_RELOC_UNUSED + 2)
#define DUMMY_RELOC_LITUSE_BYTOFF (BFD_RELOC_UNUSED + 3)
#define DUMMY_RELOC_LITUSE_JSR (BFD_RELOC_UNUSED + 4)
#define DUMMY_RELOC_LITUSE_TLSGD (BFD_RELOC_UNUSED + 5)
#define DUMMY_RELOC_LITUSE_TLSLDM (BFD_RELOC_UNUSED + 6)
#define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_tprel)
#define is_ir_num(x) (((x) & 32) == 0)
#define is_fpr_num(x) (((x) & 32) != 0)
#define regno(x) ((x) & 31)
#define note_gpreg(R) (alpha_gprmask |= (1 << (R)))
#define note_fpreg(R) (alpha_fprmask |= (1 << (R)))
#if 1
#define range_signed_16(x) \
(((offsetT) (x) >> 15) == 0 || ((offsetT) (x) >> 15) == -1)
#define range_signed_32(x) \
(((offsetT) (x) >> 31) == 0 || ((offsetT) (x) >> 31) == -1)
#else
#define range_signed_16(x) ((offsetT) (x) >= -(offsetT) 0x8000 && \
(offsetT) (x) <= (offsetT) 0x7FFF)
#define range_signed_32(x) ((offsetT) (x) >= -(offsetT) 0x80000000 && \
(offsetT) (x) <= (offsetT) 0x7FFFFFFF)
#endif
#if 1
#define sign_extend_16(x) ((short) (x))
#define sign_extend_32(x) ((int) (x))
#else
#define sign_extend_16(x) ((offsetT) (((x) & 0xFFFF) ^ 0x8000) - 0x8000)
#define sign_extend_32(x) ((offsetT) (((x) & 0xFFFFFFFF) \
^ 0x80000000) - 0x80000000)
#endif
#define set_tok_reg(t, r) (memset (&(t), 0, sizeof (t)), \
(t).X_op = O_register, \
(t).X_add_number = (r))
#define set_tok_preg(t, r) (memset (&(t), 0, sizeof (t)), \
(t).X_op = O_pregister, \
(t).X_add_number = (r))
#define set_tok_cpreg(t, r) (memset (&(t), 0, sizeof (t)), \
(t).X_op = O_cpregister, \
(t).X_add_number = (r))
#define set_tok_freg(t, r) (memset (&(t), 0, sizeof (t)), \
(t).X_op = O_register, \
(t).X_add_number = (r) + 32)
#define set_tok_sym(t, s, a) (memset (&(t), 0, sizeof (t)), \
(t).X_op = O_symbol, \
(t).X_add_symbol = (s), \
(t).X_add_number = (a))
#define set_tok_const(t, n) (memset (&(t), 0, sizeof (t)), \
(t).X_op = O_constant, \
(t).X_add_number = (n))
static struct alpha_reloc_tag *get_alpha_reloc_tag PARAMS ((long));
static void alpha_adjust_relocs PARAMS ((bfd *, asection *, PTR));
static int tokenize_arguments PARAMS ((char *, expressionS *, int));
static const struct alpha_opcode *find_opcode_match
PARAMS ((const struct alpha_opcode *, const expressionS *, int *, int *));
static const struct alpha_macro *find_macro_match
PARAMS ((const struct alpha_macro *, const expressionS *, int *));
static unsigned insert_operand
PARAMS ((unsigned, const struct alpha_operand *, offsetT, char *, unsigned));
static void assemble_insn
PARAMS ((const struct alpha_opcode *, const expressionS *, int,
struct alpha_insn *, bfd_reloc_code_real_type));
static void emit_insn PARAMS ((struct alpha_insn *));
static void assemble_tokens_to_insn
PARAMS ((const char *, const expressionS *, int, struct alpha_insn *));
static void assemble_tokens
PARAMS ((const char *, const expressionS *, int, int));
static long load_expression
PARAMS ((int, const expressionS *, int *, expressionS *));
static void emit_ldgp PARAMS ((const expressionS *, int, const PTR));
static void emit_division PARAMS ((const expressionS *, int, const PTR));
static void emit_lda PARAMS ((const expressionS *, int, const PTR));
static void emit_ldah PARAMS ((const expressionS *, int, const PTR));
static void emit_ir_load PARAMS ((const expressionS *, int, const PTR));
static void emit_loadstore PARAMS ((const expressionS *, int, const PTR));
static void emit_jsrjmp PARAMS ((const expressionS *, int, const PTR));
static void emit_ldX PARAMS ((const expressionS *, int, const PTR));
static void emit_ldXu PARAMS ((const expressionS *, int, const PTR));
static void emit_uldX PARAMS ((const expressionS *, int, const PTR));
static void emit_uldXu PARAMS ((const expressionS *, int, const PTR));
static void emit_ldil PARAMS ((const expressionS *, int, const PTR));
static void emit_stX PARAMS ((const expressionS *, int, const PTR));
static void emit_ustX PARAMS ((const expressionS *, int, const PTR));
static void emit_sextX PARAMS ((const expressionS *, int, const PTR));
static void emit_retjcr PARAMS ((const expressionS *, int, const PTR));
static void s_alpha_text PARAMS ((int));
static void s_alpha_data PARAMS ((int));
#ifndef OBJ_ELF
static void s_alpha_comm PARAMS ((int));
static void s_alpha_rdata PARAMS ((int));
#endif
#ifdef OBJ_ECOFF
static void s_alpha_sdata PARAMS ((int));
#endif
#ifdef OBJ_ELF
static void s_alpha_section PARAMS ((int));
static void s_alpha_ent PARAMS ((int));
static void s_alpha_end PARAMS ((int));
static void s_alpha_mask PARAMS ((int));
static void s_alpha_frame PARAMS ((int));
static void s_alpha_prologue PARAMS ((int));
static void s_alpha_file PARAMS ((int));
static void s_alpha_loc PARAMS ((int));
static void s_alpha_stab PARAMS ((int));
static void s_alpha_coff_wrapper PARAMS ((int));
static void s_alpha_usepv PARAMS ((int));
#endif
#ifdef OBJ_EVAX
static void s_alpha_section PARAMS ((int));
#endif
static void s_alpha_gprel32 PARAMS ((int));
static void s_alpha_float_cons PARAMS ((int));
static void s_alpha_proc PARAMS ((int));
static void s_alpha_set PARAMS ((int));
static void s_alpha_base PARAMS ((int));
static void s_alpha_align PARAMS ((int));
static void s_alpha_stringer PARAMS ((int));
static void s_alpha_space PARAMS ((int));
static void s_alpha_ucons PARAMS ((int));
static void s_alpha_arch PARAMS ((int));
static void create_literal_section PARAMS ((const char *, segT *, symbolS **));
#ifndef OBJ_ELF
static void select_gp_value PARAMS ((void));
#endif
static void alpha_align PARAMS ((int, char *, symbolS *, int));
const char comment_chars[] = "#";
const char line_comment_chars[] = "#";
const char line_separator_chars[] = ";";
const char EXP_CHARS[] = "eE";
char FLT_CHARS[] = "rRsSfFdDxXpP";
#ifdef OBJ_EVAX
const char *md_shortopts = "Fm:g+1h:HG:";
#else
const char *md_shortopts = "Fm:gG:";
#endif
struct option md_longopts[] =
{
#define OPTION_32ADDR (OPTION_MD_BASE)
{ "32addr", no_argument, NULL, OPTION_32ADDR },
#define OPTION_RELAX (OPTION_32ADDR + 1)
{ "relax", no_argument, NULL, OPTION_RELAX },
#ifdef OBJ_ELF
#define OPTION_MDEBUG (OPTION_RELAX + 1)
#define OPTION_NO_MDEBUG (OPTION_MDEBUG + 1)
{ "mdebug", no_argument, NULL, OPTION_MDEBUG },
{ "no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG },
#endif
{ NULL, no_argument, NULL, 0 }
};
size_t md_longopts_size = sizeof (md_longopts);
#ifdef OBJ_EVAX
#define AXP_REG_R0 0
#define AXP_REG_R16 16
#define AXP_REG_R17 17
#undef AXP_REG_T9
#define AXP_REG_T9 22
#undef AXP_REG_T10
#define AXP_REG_T10 23
#undef AXP_REG_T11
#define AXP_REG_T11 24
#undef AXP_REG_T12
#define AXP_REG_T12 25
#define AXP_REG_AI 25
#undef AXP_REG_FP
#define AXP_REG_FP 29
#undef AXP_REG_GP
#define AXP_REG_GP AXP_REG_PV
#endif
static unsigned alpha_target = AXP_OPCODE_BASE;
static const char *alpha_target_name = "<all>";
static struct hash_control *alpha_opcode_hash;
static struct hash_control *alpha_macro_hash;
#ifdef OBJ_ECOFF
static symbolS *alpha_gp_symbol;
valueT alpha_gp_value;
#endif
static int alpha_gp_register = AXP_REG_GP;
static symbolS *alpha_register_table[64];
#ifdef OBJ_ECOFF
static segT alpha_lita_section;
#endif
#ifdef OBJ_EVAX
static segT alpha_link_section;
static segT alpha_ctors_section;
static segT alpha_dtors_section;
#endif
static segT alpha_lit8_section;
#ifdef OBJ_ECOFF
static symbolS *alpha_lita_symbol;
#endif
#ifdef OBJ_EVAX
static symbolS *alpha_link_symbol;
static symbolS *alpha_ctors_symbol;
static symbolS *alpha_dtors_symbol;
#endif
static symbolS *alpha_lit8_symbol;
#ifdef OBJ_ECOFF
static offsetT alpha_lit8_literal;
#endif
static int alpha_noat_on = 0;
static int alpha_macros_on = 1;
static int alpha_nofloats_on = 0;
static int alpha_addr32_on = 0;
static symbolS *alpha_insn_label;
static int alpha_auto_align_on = 1;
static int alpha_current_align;
unsigned long alpha_gprmask, alpha_fprmask;
static int alpha_debug;
#ifdef OBJ_ELF
int alpha_flag_mdebug = -1;
#endif
static int alpha_flag_relax;
static int g_switch_value = 8;
#ifdef OBJ_EVAX
static struct {
symbolS *symbol;
int pdsckind;
int framereg;
int framesize;
int rsa_offset;
int ra_save;
int fp_save;
long imask;
long fmask;
int type;
int prologue;
} alpha_evax_proc;
static int alpha_flag_hash_long_names = 0;
static int alpha_flag_show_after_trunc = 0;
#endif
#ifdef RELOC_OP_P
#define ALPHA_RELOC_TABLE(op) \
(&alpha_reloc_op[ ((!USER_RELOC_P (op)) \
? (abort (), 0) \
: (int) (op) - (int) O_literal) ])
#define DEF(NAME, RELOC, REQ, ALLOW) \
{ #NAME, sizeof(#NAME)-1, O_##NAME, RELOC, REQ, ALLOW}
static const struct alpha_reloc_op_tag
{
const char *name;
size_t length;
operatorT op;
bfd_reloc_code_real_type reloc;
unsigned int require_seq : 1;
unsigned int allow_seq : 1;
}
alpha_reloc_op[] =
{
DEF(literal, BFD_RELOC_ALPHA_ELF_LITERAL, 0, 1),
DEF(lituse_addr, DUMMY_RELOC_LITUSE_ADDR, 1, 1),
DEF(lituse_base, DUMMY_RELOC_LITUSE_BASE, 1, 1),
DEF(lituse_bytoff, DUMMY_RELOC_LITUSE_BYTOFF, 1, 1),
DEF(lituse_jsr, DUMMY_RELOC_LITUSE_JSR, 1, 1),
DEF(lituse_tlsgd, DUMMY_RELOC_LITUSE_TLSGD, 1, 1),
DEF(lituse_tlsldm, DUMMY_RELOC_LITUSE_TLSLDM, 1, 1),
DEF(gpdisp, BFD_RELOC_ALPHA_GPDISP, 1, 1),
DEF(gprelhigh, BFD_RELOC_ALPHA_GPREL_HI16, 0, 0),
DEF(gprellow, BFD_RELOC_ALPHA_GPREL_LO16, 0, 0),
DEF(gprel, BFD_RELOC_GPREL16, 0, 0),
DEF(samegp, BFD_RELOC_ALPHA_BRSGP, 0, 0),
DEF(tlsgd, BFD_RELOC_ALPHA_TLSGD, 0, 1),
DEF(tlsldm, BFD_RELOC_ALPHA_TLSLDM, 0, 1),
DEF(gotdtprel, BFD_RELOC_ALPHA_GOTDTPREL16, 0, 0),
DEF(dtprelhi, BFD_RELOC_ALPHA_DTPREL_HI16, 0, 0),
DEF(dtprello, BFD_RELOC_ALPHA_DTPREL_LO16, 0, 0),
DEF(dtprel, BFD_RELOC_ALPHA_DTPREL16, 0, 0),
DEF(gottprel, BFD_RELOC_ALPHA_GOTTPREL16, 0, 0),
DEF(tprelhi, BFD_RELOC_ALPHA_TPREL_HI16, 0, 0),
DEF(tprello, BFD_RELOC_ALPHA_TPREL_LO16, 0, 0),
DEF(tprel, BFD_RELOC_ALPHA_TPREL16, 0, 0),
};
#undef DEF
static const int alpha_num_reloc_op
= sizeof (alpha_reloc_op) / sizeof (*alpha_reloc_op);
#endif
#define ALPHA_RELOC_DIGITS 25
struct alpha_reloc_tag
{
fixS *master;
fixS *slaves;
segT segment;
long sequence;
unsigned n_master;
unsigned n_slaves;
unsigned saw_tlsgd : 1;
unsigned saw_tlsldm : 1;
unsigned saw_lu_tlsgd : 1;
unsigned saw_lu_tlsldm : 1;
unsigned multi_section_p : 1;
char string[1];
};
static struct hash_control *alpha_literal_hash;
static long next_sequence_num = -1;
static const struct cpu_type
{
const char *name;
unsigned flags;
}
cpu_types[] =
{
{ "21064", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
{ "21064a", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
{ "21066", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
{ "21068", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
{ "21164", AXP_OPCODE_BASE|AXP_OPCODE_EV5 },
{ "21164a", AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX },
{ "21164pc", (AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX
|AXP_OPCODE_MAX) },
{ "21264", (AXP_OPCODE_BASE|AXP_OPCODE_EV6|AXP_OPCODE_BWX
|AXP_OPCODE_MAX|AXP_OPCODE_CIX) },
{ "21264a", (AXP_OPCODE_BASE|AXP_OPCODE_EV6|AXP_OPCODE_BWX
|AXP_OPCODE_MAX|AXP_OPCODE_CIX) },
{ "21264b", (AXP_OPCODE_BASE|AXP_OPCODE_EV6|AXP_OPCODE_BWX
|AXP_OPCODE_MAX|AXP_OPCODE_CIX) },
{ "ev4", AXP_OPCODE_BASE },
{ "ev45", AXP_OPCODE_BASE },
{ "lca45", AXP_OPCODE_BASE },
{ "ev5", AXP_OPCODE_BASE },
{ "ev56", AXP_OPCODE_BASE|AXP_OPCODE_BWX },
{ "pca56", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX },
{ "ev6", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX|AXP_OPCODE_CIX },
{ "ev67", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX|AXP_OPCODE_CIX },
{ "ev68", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX|AXP_OPCODE_CIX },
{ "all", AXP_OPCODE_BASE },
{ 0, 0 }
};
static const struct alpha_macro alpha_macros[] =
{
{ "lda", emit_lda, NULL,
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ldah", emit_ldah, NULL,
{ MACRO_IR, MACRO_EXP, MACRO_EOA } },
{ "ldl", emit_ir_load, "ldl",
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ldl_l", emit_ir_load, "ldl_l",
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ldq", emit_ir_load, "ldq",
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ldq_l", emit_ir_load, "ldq_l",
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ldq_u", emit_ir_load, "ldq_u",
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ldf", emit_loadstore, "ldf",
{ MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ldg", emit_loadstore, "ldg",
{ MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "lds", emit_loadstore, "lds",
{ MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ldt", emit_loadstore, "ldt",
{ MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ldb", emit_ldX, (PTR) 0,
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ldbu", emit_ldXu, (PTR) 0,
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ldw", emit_ldX, (PTR) 1,
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ldwu", emit_ldXu, (PTR) 1,
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "uldw", emit_uldX, (PTR) 1,
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "uldwu", emit_uldXu, (PTR) 1,
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "uldl", emit_uldX, (PTR) 2,
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "uldlu", emit_uldXu, (PTR) 2,
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "uldq", emit_uldXu, (PTR) 3,
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ldgp", emit_ldgp, NULL,
{ MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA } },
{ "ldi", emit_lda, NULL,
{ MACRO_IR, MACRO_EXP, MACRO_EOA } },
{ "ldil", emit_ldil, NULL,
{ MACRO_IR, MACRO_EXP, MACRO_EOA } },
{ "ldiq", emit_lda, NULL,
{ MACRO_IR, MACRO_EXP, MACRO_EOA } },
{ "stl", emit_loadstore, "stl",
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "stl_c", emit_loadstore, "stl_c",
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "stq", emit_loadstore, "stq",
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "stq_c", emit_loadstore, "stq_c",
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "stq_u", emit_loadstore, "stq_u",
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "stf", emit_loadstore, "stf",
{ MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "stg", emit_loadstore, "stg",
{ MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "sts", emit_loadstore, "sts",
{ MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "stt", emit_loadstore, "stt",
{ MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "stb", emit_stX, (PTR) 0,
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "stw", emit_stX, (PTR) 1,
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ustw", emit_ustX, (PTR) 1,
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ustl", emit_ustX, (PTR) 2,
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "ustq", emit_ustX, (PTR) 3,
{ MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } },
{ "sextb", emit_sextX, (PTR) 0,
{ MACRO_IR, MACRO_IR, MACRO_EOA,
MACRO_IR, MACRO_EOA,
} },
{ "sextw", emit_sextX, (PTR) 1,
{ MACRO_IR, MACRO_IR, MACRO_EOA,
MACRO_IR, MACRO_EOA,
} },
{ "divl", emit_division, "__divl",
{ MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
MACRO_IR, MACRO_IR, MACRO_EOA,
} },
{ "divlu", emit_division, "__divlu",
{ MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
MACRO_IR, MACRO_IR, MACRO_EOA,
} },
{ "divq", emit_division, "__divq",
{ MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
MACRO_IR, MACRO_IR, MACRO_EOA,
} },
{ "divqu", emit_division, "__divqu",
{ MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
MACRO_IR, MACRO_IR, MACRO_EOA,
} },
{ "reml", emit_division, "__reml",
{ MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
MACRO_IR, MACRO_IR, MACRO_EOA,
} },
{ "remlu", emit_division, "__remlu",
{ MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
MACRO_IR, MACRO_IR, MACRO_EOA,
} },
{ "remq", emit_division, "__remq",
{ MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
MACRO_IR, MACRO_IR, MACRO_EOA,
} },
{ "remqu", emit_division, "__remqu",
{ MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA,
MACRO_IR, MACRO_IR, MACRO_EOA,
} },
{ "jsr", emit_jsrjmp, "jsr",
{ MACRO_PIR, MACRO_EXP, MACRO_EOA,
MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA,
MACRO_EXP, MACRO_EOA } },
{ "jmp", emit_jsrjmp, "jmp",
{ MACRO_PIR, MACRO_EXP, MACRO_EOA,
MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA,
MACRO_EXP, MACRO_EOA } },
{ "ret", emit_retjcr, "ret",
{ MACRO_IR, MACRO_EXP, MACRO_EOA,
MACRO_IR, MACRO_EOA,
MACRO_PIR, MACRO_EXP, MACRO_EOA,
MACRO_PIR, MACRO_EOA,
MACRO_EXP, MACRO_EOA,
MACRO_EOA } },
{ "jcr", emit_retjcr, "jcr",
{ MACRO_IR, MACRO_EXP, MACRO_EOA,
MACRO_IR, MACRO_EOA,
MACRO_PIR, MACRO_EXP, MACRO_EOA,
MACRO_PIR, MACRO_EOA,
MACRO_EXP, MACRO_EOA,
MACRO_EOA } },
{ "jsr_coroutine", emit_retjcr, "jcr",
{ MACRO_IR, MACRO_EXP, MACRO_EOA,
MACRO_IR, MACRO_EOA,
MACRO_PIR, MACRO_EXP, MACRO_EOA,
MACRO_PIR, MACRO_EOA,
MACRO_EXP, MACRO_EOA,
MACRO_EOA } },
};
static const unsigned int alpha_num_macros
= sizeof (alpha_macros) / sizeof (*alpha_macros);
void
md_begin ()
{
unsigned int i;
{
expressionS e;
e.X_op = O_max;
assert (e.X_op == O_max);
}
alpha_opcode_hash = hash_new ();
for (i = 0; i < alpha_num_opcodes;)
{
const char *name, *retval, *slash;
name = alpha_opcodes[i].name;
retval = hash_insert (alpha_opcode_hash, name, (PTR) &alpha_opcodes[i]);
if (retval)
as_fatal (_("internal error: can't hash opcode `%s': %s"),
name, retval);
if ((slash = strchr (name, '/')) != NULL)
{
char *p = xmalloc (strlen (name));
memcpy (p, name, slash - name);
strcpy (p + (slash - name), slash + 1);
(void) hash_insert (alpha_opcode_hash, p, (PTR) &alpha_opcodes[i]);
}
while (++i < alpha_num_opcodes
&& (alpha_opcodes[i].name == name
|| !strcmp (alpha_opcodes[i].name, name)))
continue;
}
alpha_macro_hash = hash_new ();
for (i = 0; i < alpha_num_macros;)
{
const char *name, *retval;
name = alpha_macros[i].name;
retval = hash_insert (alpha_macro_hash, name, (PTR) &alpha_macros[i]);
if (retval)
as_fatal (_("internal error: can't hash macro `%s': %s"),
name, retval);
while (++i < alpha_num_macros
&& (alpha_macros[i].name == name
|| !strcmp (alpha_macros[i].name, name)))
continue;
}
for (i = 0; i < 32; ++i)
{
char name[4];
sprintf (name, "$%d", i);
alpha_register_table[i] = symbol_create (name, reg_section, i,
&zero_address_frag);
}
for (; i < 64; ++i)
{
char name[5];
sprintf (name, "$f%d", i - 32);
alpha_register_table[i] = symbol_create (name, reg_section, i,
&zero_address_frag);
}
bfd_set_gp_size (stdoutput, g_switch_value);
#ifdef OBJ_ECOFF
create_literal_section (".lita", &alpha_lita_section, &alpha_lita_symbol);
alpha_gp_symbol = symbol_create ("<GP value>", alpha_lita_section, 0x8000,
&zero_address_frag);
#endif
#ifdef OBJ_EVAX
create_literal_section (".link", &alpha_link_section, &alpha_link_symbol);
#endif
#ifdef OBJ_ELF
if (ECOFF_DEBUGGING)
{
segT sec = subseg_new (".mdebug", (subsegT) 0);
bfd_set_section_flags (stdoutput, sec, SEC_HAS_CONTENTS | SEC_READONLY);
bfd_set_section_alignment (stdoutput, sec, 3);
}
#endif
alpha_literal_hash = hash_new ();
subseg_set (text_section, 0);
}
void
md_assemble (str)
char *str;
{
char opname[32];
expressionS tok[MAX_INSN_ARGS];
int ntok, trunclen;
size_t opnamelen;
opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_/46819");
trunclen = (opnamelen < sizeof (opname) - 1
? opnamelen
: sizeof (opname) - 1);
memcpy (opname, str, trunclen);
opname[trunclen] = '\0';
if ((ntok = tokenize_arguments (str + opnamelen, tok, MAX_INSN_ARGS)) < 0)
{
if (ntok != TOKENIZE_ERROR_REPORT)
as_bad (_("syntax error"));
return;
}
assemble_tokens (opname, tok, ntok, alpha_macros_on);
}
valueT
md_section_align (seg, size)
segT seg;
valueT size;
{
int align = bfd_get_section_alignment (stdoutput, seg);
valueT mask = ((valueT) 1 << align) - 1;
return (size + mask) & ~mask;
}
#define MAX_LITTLENUMS 6
extern char *vax_md_atof PARAMS ((int, char *, int *));
char *
md_atof (type, litP, sizeP)
char type;
char *litP;
int *sizeP;
{
int prec;
LITTLENUM_TYPE words[MAX_LITTLENUMS];
LITTLENUM_TYPE *wordP;
char *t;
switch (type)
{
case 'G':
type = 'g';
case 'F':
case 'D':
return vax_md_atof (type, litP, sizeP);
case 'f':
prec = 2;
break;
case 'd':
prec = 4;
break;
case 'x':
case 'X':
prec = 6;
break;
case 'p':
case 'P':
prec = 6;
break;
default:
*sizeP = 0;
return _("Bad call to MD_ATOF()");
}
t = atof_ieee (input_line_pointer, type, words);
if (t)
input_line_pointer = t;
*sizeP = prec * sizeof (LITTLENUM_TYPE);
for (wordP = words + prec - 1; prec--;)
{
md_number_to_chars (litP, (long) (*wordP--), sizeof (LITTLENUM_TYPE));
litP += sizeof (LITTLENUM_TYPE);
}
return 0;
}
int
md_parse_option (c, arg)
int c;
char *arg;
{
switch (c)
{
case 'F':
alpha_nofloats_on = 1;
break;
case OPTION_32ADDR:
alpha_addr32_on = 1;
break;
case 'g':
alpha_debug = 1;
break;
case 'G':
g_switch_value = atoi (arg);
break;
case 'm':
{
const struct cpu_type *p;
for (p = cpu_types; p->name; ++p)
if (strcmp (arg, p->name) == 0)
{
alpha_target_name = p->name, alpha_target = p->flags;
goto found;
}
as_warn (_("Unknown CPU identifier `%s'"), arg);
found:;
}
break;
#ifdef OBJ_EVAX
case '+':
alpha_flag_hash_long_names = 1;
break;
case 'H':
alpha_flag_show_after_trunc = 1;
break;
case 'h':
break;
#endif
case OPTION_RELAX:
alpha_flag_relax = 1;
break;
#ifdef OBJ_ELF
case OPTION_MDEBUG:
alpha_flag_mdebug = 1;
break;
case OPTION_NO_MDEBUG:
alpha_flag_mdebug = 0;
break;
#endif
default:
return 0;
}
return 1;
}
void
md_show_usage (stream)
FILE *stream;
{
fputs (_("\
Alpha options:\n\
-32addr treat addresses as 32-bit values\n\
-F lack floating point instructions support\n\
-mev4 | -mev45 | -mev5 | -mev56 | -mpca56 | -mev6 | -mev67 | -mev68 | -mall\n\
specify variant of Alpha architecture\n\
-m21064 | -m21066 | -m21164 | -m21164a | -m21164pc | -m21264 | -m21264a | -m21264b\n\
these variants include PALcode opcodes\n"),
stream);
#ifdef OBJ_EVAX
fputs (_("\
VMS options:\n\
-+ hash encode (don't truncate) names longer than 64 characters\n\
-H show new symbol after hash truncation\n"),
stream);
#endif
}
long
md_pcrel_from (fixP)
fixS *fixP;
{
valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
switch (fixP->fx_r_type)
{
case BFD_RELOC_23_PCREL_S2:
case BFD_RELOC_ALPHA_HINT:
case BFD_RELOC_ALPHA_BRSGP:
return addr + 4;
default:
return addr;
}
}
void
md_apply_fix3 (fixP, valP, seg)
fixS *fixP;
valueT * valP;
segT seg;
{
char * const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
valueT value = * valP;
unsigned image, size;
switch (fixP->fx_r_type)
{
case BFD_RELOC_ALPHA_GPDISP_HI16:
{
fixS *next = fixP->fx_next;
if (next)
fixP->fx_offset = (next->fx_frag->fr_address + next->fx_where
- fixP->fx_frag->fr_address - fixP->fx_where);
value = (value - sign_extend_16 (value)) >> 16;
}
#ifdef OBJ_ELF
fixP->fx_r_type = BFD_RELOC_ALPHA_GPDISP;
#endif
goto do_reloc_gp;
case BFD_RELOC_ALPHA_GPDISP_LO16:
value = sign_extend_16 (value);
fixP->fx_offset = 0;
#ifdef OBJ_ELF
fixP->fx_done = 1;
#endif
do_reloc_gp:
fixP->fx_addsy = section_symbol (seg);
md_number_to_chars (fixpos, value, 2);
break;
case BFD_RELOC_16:
if (fixP->fx_pcrel)
fixP->fx_r_type = BFD_RELOC_16_PCREL;
size = 2;
goto do_reloc_xx;
case BFD_RELOC_32:
if (fixP->fx_pcrel)
fixP->fx_r_type = BFD_RELOC_32_PCREL;
size = 4;
goto do_reloc_xx;
case BFD_RELOC_64:
if (fixP->fx_pcrel)
fixP->fx_r_type = BFD_RELOC_64_PCREL;
size = 8;
do_reloc_xx:
if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0)
{
md_number_to_chars (fixpos, value, size);
goto done;
}
return;
#ifdef OBJ_ECOFF
case BFD_RELOC_GPREL32:
assert (fixP->fx_subsy == alpha_gp_symbol);
fixP->fx_subsy = 0;
md_number_to_chars (fixpos, -alpha_gp_value, 4);
break;
#else
case BFD_RELOC_GPREL32:
#endif
case BFD_RELOC_GPREL16:
case BFD_RELOC_ALPHA_GPREL_HI16:
case BFD_RELOC_ALPHA_GPREL_LO16:
return;
case BFD_RELOC_23_PCREL_S2:
if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0)
{
image = bfd_getl32 (fixpos);
image = (image & ~0x1FFFFF) | ((value >> 2) & 0x1FFFFF);
goto write_done;
}
return;
case BFD_RELOC_ALPHA_HINT:
if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0)
{
image = bfd_getl32 (fixpos);
image = (image & ~0x3FFF) | ((value >> 2) & 0x3FFF);
goto write_done;
}
return;
#ifdef OBJ_ELF
case BFD_RELOC_ALPHA_BRSGP:
return;
case BFD_RELOC_ALPHA_TLSGD:
case BFD_RELOC_ALPHA_TLSLDM:
case BFD_RELOC_ALPHA_GOTDTPREL16:
case BFD_RELOC_ALPHA_DTPREL_HI16:
case BFD_RELOC_ALPHA_DTPREL_LO16:
case BFD_RELOC_ALPHA_DTPREL16:
case BFD_RELOC_ALPHA_GOTTPREL16:
case BFD_RELOC_ALPHA_TPREL_HI16:
case BFD_RELOC_ALPHA_TPREL_LO16:
case BFD_RELOC_ALPHA_TPREL16:
if (fixP->fx_addsy)
S_SET_THREAD_LOCAL (fixP->fx_addsy);
return;
#endif
#ifdef OBJ_ECOFF
case BFD_RELOC_ALPHA_LITERAL:
md_number_to_chars (fixpos, value, 2);
return;
#endif
case BFD_RELOC_ALPHA_ELF_LITERAL:
case BFD_RELOC_ALPHA_LITUSE:
case BFD_RELOC_ALPHA_LINKAGE:
case BFD_RELOC_ALPHA_CODEADDR:
return;
case BFD_RELOC_VTABLE_INHERIT:
case BFD_RELOC_VTABLE_ENTRY:
return;
default:
{
const struct alpha_operand *operand;
if ((int) fixP->fx_r_type >= 0)
as_fatal (_("unhandled relocation type %s"),
bfd_get_reloc_code_name (fixP->fx_r_type));
assert (-(int) fixP->fx_r_type < (int) alpha_num_operands);
operand = &alpha_operands[-(int) fixP->fx_r_type];
if (fixP->fx_addsy != 0
&& S_GET_SEGMENT (fixP->fx_addsy) != absolute_section)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("non-absolute expression in constant field"));
image = bfd_getl32 (fixpos);
image = insert_operand (image, operand, (offsetT) value,
fixP->fx_file, fixP->fx_line);
}
goto write_done;
}
if (fixP->fx_addsy != 0 || fixP->fx_pcrel != 0)
return;
else
{
as_warn_where (fixP->fx_file, fixP->fx_line,
_("type %d reloc done?\n"), (int) fixP->fx_r_type);
goto done;
}
write_done:
md_number_to_chars (fixpos, image, 4);
done:
fixP->fx_done = 1;
}
symbolS *
md_undefined_symbol (name)
char *name;
{
if (*name == '$')
{
int is_float = 0, num;
switch (*++name)
{
case 'f':
if (name[1] == 'p' && name[2] == '\0')
return alpha_register_table[AXP_REG_FP];
is_float = 32;
case 'r':
if (!ISDIGIT (*++name))
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (name[1] == '\0')
num = name[0] - '0';
else if (name[0] != '0' && ISDIGIT (name[1]) && name[2] == '\0')
{
num = (name[0] - '0') * 10 + name[1] - '0';
if (num >= 32)
break;
}
else
break;
if (!alpha_noat_on && (num + is_float) == AXP_REG_AT)
as_warn (_("Used $at without \".set noat\""));
return alpha_register_table[num + is_float];
case 'a':
if (name[1] == 't' && name[2] == '\0')
{
if (!alpha_noat_on)
as_warn (_("Used $at without \".set noat\""));
return alpha_register_table[AXP_REG_AT];
}
break;
case 'g':
if (name[1] == 'p' && name[2] == '\0')
return alpha_register_table[alpha_gp_register];
break;
case 's':
if (name[1] == 'p' && name[2] == '\0')
return alpha_register_table[AXP_REG_SP];
break;
}
}
return NULL;
}
#ifdef OBJ_ECOFF
void
alpha_frob_ecoff_data ()
{
select_gp_value ();
alpha_gprmask &= ~1;
alpha_fprmask &= ~1;
}
#endif
void
alpha_define_label (sym)
symbolS *sym;
{
alpha_insn_label = sym;
}
int
alpha_force_relocation (f)
fixS *f;
{
if (alpha_flag_relax)
return 1;
switch (f->fx_r_type)
{
case BFD_RELOC_ALPHA_GPDISP_HI16:
case BFD_RELOC_ALPHA_GPDISP_LO16:
case BFD_RELOC_ALPHA_GPDISP:
case BFD_RELOC_ALPHA_LITERAL:
case BFD_RELOC_ALPHA_ELF_LITERAL:
case BFD_RELOC_ALPHA_LITUSE:
case BFD_RELOC_GPREL16:
case BFD_RELOC_GPREL32:
case BFD_RELOC_ALPHA_GPREL_HI16:
case BFD_RELOC_ALPHA_GPREL_LO16:
case BFD_RELOC_ALPHA_LINKAGE:
case BFD_RELOC_ALPHA_CODEADDR:
case BFD_RELOC_ALPHA_BRSGP:
case BFD_RELOC_ALPHA_TLSGD:
case BFD_RELOC_ALPHA_TLSLDM:
case BFD_RELOC_ALPHA_GOTDTPREL16:
case BFD_RELOC_ALPHA_DTPREL_HI16:
case BFD_RELOC_ALPHA_DTPREL_LO16:
case BFD_RELOC_ALPHA_DTPREL16:
case BFD_RELOC_ALPHA_GOTTPREL16:
case BFD_RELOC_ALPHA_TPREL_HI16:
case BFD_RELOC_ALPHA_TPREL_LO16:
case BFD_RELOC_ALPHA_TPREL16:
return 1;
default:
break;
}
return generic_force_reloc (f);
}
int
alpha_fix_adjustable (f)
fixS *f;
{
switch (f->fx_r_type)
{
case BFD_RELOC_ALPHA_GPDISP_HI16:
case BFD_RELOC_ALPHA_GPDISP_LO16:
case BFD_RELOC_ALPHA_GPDISP:
return 0;
case BFD_RELOC_ALPHA_LITERAL:
case BFD_RELOC_ALPHA_ELF_LITERAL:
case BFD_RELOC_ALPHA_LITUSE:
case BFD_RELOC_ALPHA_LINKAGE:
case BFD_RELOC_ALPHA_CODEADDR:
return 1;
case BFD_RELOC_VTABLE_ENTRY:
case BFD_RELOC_VTABLE_INHERIT:
return 0;
case BFD_RELOC_GPREL16:
case BFD_RELOC_GPREL32:
case BFD_RELOC_ALPHA_GPREL_HI16:
case BFD_RELOC_ALPHA_GPREL_LO16:
case BFD_RELOC_23_PCREL_S2:
case BFD_RELOC_32:
case BFD_RELOC_64:
case BFD_RELOC_ALPHA_HINT:
return 1;
case BFD_RELOC_ALPHA_TLSGD:
case BFD_RELOC_ALPHA_TLSLDM:
case BFD_RELOC_ALPHA_GOTDTPREL16:
case BFD_RELOC_ALPHA_DTPREL_HI16:
case BFD_RELOC_ALPHA_DTPREL_LO16:
case BFD_RELOC_ALPHA_DTPREL16:
case BFD_RELOC_ALPHA_GOTTPREL16:
case BFD_RELOC_ALPHA_TPREL_HI16:
case BFD_RELOC_ALPHA_TPREL_LO16:
case BFD_RELOC_ALPHA_TPREL16:
return 0;
#ifdef OBJ_ELF
case BFD_RELOC_ALPHA_BRSGP:
{
symbolS *sym = f->fx_addsy;
const char *name;
int offset = 0;
if (generic_force_reloc (f))
return 0;
switch (S_GET_OTHER (sym) & STO_ALPHA_STD_GPLOAD)
{
case STO_ALPHA_NOPV:
break;
case STO_ALPHA_STD_GPLOAD:
offset = 8;
break;
default:
if (S_IS_LOCAL (sym))
name = "<local>";
else
name = S_GET_NAME (sym);
as_bad_where (f->fx_file, f->fx_line,
_("!samegp reloc against symbol without .prologue: %s"),
name);
break;
}
f->fx_r_type = BFD_RELOC_23_PCREL_S2;
f->fx_offset += offset;
return 1;
}
#endif
default:
return 1;
}
}
arelent *
tc_gen_reloc (sec, fixp)
asection *sec ATTRIBUTE_UNUSED;
fixS *fixp;
{
arelent *reloc;
reloc = (arelent *) xmalloc (sizeof (arelent));
reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
assert ((int) fixp->fx_r_type > 0);
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
if (reloc->howto == NULL)
{
as_bad_where (fixp->fx_file, fixp->fx_line,
_("cannot represent `%s' relocation in object file"),
bfd_get_reloc_code_name (fixp->fx_r_type));
return NULL;
}
if (!fixp->fx_pcrel != !reloc->howto->pc_relative)
{
as_fatal (_("internal error? cannot generate `%s' relocation"),
bfd_get_reloc_code_name (fixp->fx_r_type));
}
assert (!fixp->fx_pcrel == !reloc->howto->pc_relative);
#ifdef OBJ_ECOFF
if (fixp->fx_r_type == BFD_RELOC_ALPHA_LITERAL)
{
reloc->addend = -alpha_gp_value;
}
else
#endif
{
reloc->addend = fixp->fx_offset;
#ifdef OBJ_ELF
if ((S_IS_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)
|| (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE)
|| (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_THREAD_LOCAL))
&& !S_IS_COMMON (fixp->fx_addsy))
reloc->addend -= symbol_get_bfdsym (fixp->fx_addsy)->value;
#endif
}
return reloc;
}
int
tc_get_register (frame)
int frame ATTRIBUTE_UNUSED;
{
int framereg = AXP_REG_SP;
SKIP_WHITESPACE ();
if (*input_line_pointer == '$')
{
char *s = input_line_pointer;
char c = get_symbol_end ();
symbolS *sym = md_undefined_symbol (s);
*strchr (s, '\0') = c;
if (sym && (framereg = S_GET_VALUE (sym)) <= 31)
goto found;
}
as_warn (_("frame reg expected, using $%d."), framereg);
found:
note_gpreg (framereg);
return framereg;
}
#ifdef OBJ_ECOFF
void
alpha_frob_file_before_adjust ()
{
if (alpha_debug != 0
&& ! ecoff_debugging_seen)
flag_keep_locals = 1;
}
#endif
static struct alpha_reloc_tag *
get_alpha_reloc_tag (sequence)
long sequence;
{
char buffer[ALPHA_RELOC_DIGITS];
struct alpha_reloc_tag *info;
sprintf (buffer, "!%ld", sequence);
info = (struct alpha_reloc_tag *) hash_find (alpha_literal_hash, buffer);
if (! info)
{
size_t len = strlen (buffer);
const char *errmsg;
info = (struct alpha_reloc_tag *)
xcalloc (sizeof (struct alpha_reloc_tag) + len, 1);
info->segment = now_seg;
info->sequence = sequence;
strcpy (info->string, buffer);
errmsg = hash_insert (alpha_literal_hash, info->string, (PTR) info);
if (errmsg)
as_fatal (errmsg);
}
return info;
}
void
alpha_before_fix ()
{
if (alpha_literal_hash)
bfd_map_over_sections (stdoutput, alpha_adjust_relocs, NULL);
}
static void
alpha_adjust_relocs (abfd, sec, ptr)
bfd *abfd ATTRIBUTE_UNUSED;
asection *sec;
PTR ptr ATTRIBUTE_UNUSED;
{
segment_info_type *seginfo = seg_info (sec);
fixS **prevP;
fixS *fixp;
fixS *next;
fixS *slave;
if (seginfo == NULL)
return;
if (! seginfo->fix_root)
return;
prevP = &seginfo->fix_root;
for (fixp = seginfo->fix_root; fixp; fixp = next)
{
next = fixp->fx_next;
fixp->fx_next = (fixS *) 0;
switch (fixp->fx_r_type)
{
case BFD_RELOC_ALPHA_LITUSE:
if (fixp->tc_fix_data.info->n_master == 0)
as_bad_where (fixp->fx_file, fixp->fx_line,
_("No !literal!%ld was found"),
fixp->tc_fix_data.info->sequence);
#ifdef RELOC_OP_P
if (fixp->fx_offset == LITUSE_ALPHA_TLSGD)
{
if (! fixp->tc_fix_data.info->saw_tlsgd)
as_bad_where (fixp->fx_file, fixp->fx_line,
_("No !tlsgd!%ld was found"),
fixp->tc_fix_data.info->sequence);
}
else if (fixp->fx_offset == LITUSE_ALPHA_TLSLDM)
{
if (! fixp->tc_fix_data.info->saw_tlsldm)
as_bad_where (fixp->fx_file, fixp->fx_line,
_("No !tlsldm!%ld was found"),
fixp->tc_fix_data.info->sequence);
}
#endif
break;
case BFD_RELOC_ALPHA_GPDISP_LO16:
if (fixp->tc_fix_data.info->n_master == 0)
as_bad_where (fixp->fx_file, fixp->fx_line,
_("No ldah !gpdisp!%ld was found"),
fixp->tc_fix_data.info->sequence);
break;
case BFD_RELOC_ALPHA_ELF_LITERAL:
if (fixp->tc_fix_data.info
&& (fixp->tc_fix_data.info->saw_tlsgd
|| fixp->tc_fix_data.info->saw_tlsldm))
break;
default:
*prevP = fixp;
prevP = &fixp->fx_next;
break;
}
}
for (fixp = seginfo->fix_root; fixp; fixp = next)
{
next = fixp->fx_next;
switch (fixp->fx_r_type)
{
case BFD_RELOC_ALPHA_TLSGD:
case BFD_RELOC_ALPHA_TLSLDM:
if (!fixp->tc_fix_data.info)
break;
if (fixp->tc_fix_data.info->n_master == 0)
break;
else if (fixp->tc_fix_data.info->n_master > 1)
{
as_bad_where (fixp->fx_file, fixp->fx_line,
_("too many !literal!%ld for %s"),
fixp->tc_fix_data.info->sequence,
(fixp->fx_r_type == BFD_RELOC_ALPHA_TLSGD
? "!tlsgd" : "!tlsldm"));
break;
}
fixp->tc_fix_data.info->master->fx_next = fixp->fx_next;
fixp->fx_next = fixp->tc_fix_data.info->master;
fixp = fixp->fx_next;
case BFD_RELOC_ALPHA_ELF_LITERAL:
if (fixp->tc_fix_data.info
&& fixp->tc_fix_data.info->n_master == 1
&& ! fixp->tc_fix_data.info->multi_section_p)
{
for (slave = fixp->tc_fix_data.info->slaves;
slave != (fixS *) 0;
slave = slave->tc_fix_data.next_reloc)
{
slave->fx_next = fixp->fx_next;
fixp->fx_next = slave;
}
}
break;
case BFD_RELOC_ALPHA_GPDISP_HI16:
if (fixp->tc_fix_data.info->n_slaves == 0)
as_bad_where (fixp->fx_file, fixp->fx_line,
_("No lda !gpdisp!%ld was found"),
fixp->tc_fix_data.info->sequence);
else
{
slave = fixp->tc_fix_data.info->slaves;
slave->fx_next = next;
fixp->fx_next = slave;
}
break;
default:
break;
}
}
}
#ifdef DEBUG_ALPHA
static void
debug_exp (tok, ntok)
expressionS tok[];
int ntok;
{
int i;
fprintf (stderr, "debug_exp: %d tokens", ntok);
for (i = 0; i < ntok; i++)
{
expressionS *t = &tok[i];
const char *name;
switch (t->X_op)
{
default: name = "unknown"; break;
case O_illegal: name = "O_illegal"; break;
case O_absent: name = "O_absent"; break;
case O_constant: name = "O_constant"; break;
case O_symbol: name = "O_symbol"; break;
case O_symbol_rva: name = "O_symbol_rva"; break;
case O_register: name = "O_register"; break;
case O_big: name = "O_big"; break;
case O_uminus: name = "O_uminus"; break;
case O_bit_not: name = "O_bit_not"; break;
case O_logical_not: name = "O_logical_not"; break;
case O_multiply: name = "O_multiply"; break;
case O_divide: name = "O_divide"; break;
case O_modulus: name = "O_modulus"; break;
case O_left_shift: name = "O_left_shift"; break;
case O_right_shift: name = "O_right_shift"; break;
case O_bit_inclusive_or: name = "O_bit_inclusive_or"; break;
case O_bit_or_not: name = "O_bit_or_not"; break;
case O_bit_exclusive_or: name = "O_bit_exclusive_or"; break;
case O_bit_and: name = "O_bit_and"; break;
case O_add: name = "O_add"; break;
case O_subtract: name = "O_subtract"; break;
case O_eq: name = "O_eq"; break;
case O_ne: name = "O_ne"; break;
case O_lt: name = "O_lt"; break;
case O_le: name = "O_le"; break;
case O_ge: name = "O_ge"; break;
case O_gt: name = "O_gt"; break;
case O_logical_and: name = "O_logical_and"; break;
case O_logical_or: name = "O_logical_or"; break;
case O_index: name = "O_index"; break;
case O_pregister: name = "O_pregister"; break;
case O_cpregister: name = "O_cpregister"; break;
case O_literal: name = "O_literal"; break;
case O_lituse_addr: name = "O_lituse_addr"; break;
case O_lituse_base: name = "O_lituse_base"; break;
case O_lituse_bytoff: name = "O_lituse_bytoff"; break;
case O_lituse_jsr: name = "O_lituse_jsr"; break;
case O_lituse_tlsgd: name = "O_lituse_tlsgd"; break;
case O_lituse_tlsldm: name = "O_lituse_tlsldm"; break;
case O_gpdisp: name = "O_gpdisp"; break;
case O_gprelhigh: name = "O_gprelhigh"; break;
case O_gprellow: name = "O_gprellow"; break;
case O_gprel: name = "O_gprel"; break;
case O_samegp: name = "O_samegp"; break;
case O_tlsgd: name = "O_tlsgd"; break;
case O_tlsldm: name = "O_tlsldm"; break;
case O_gotdtprel: name = "O_gotdtprel"; break;
case O_dtprelhi: name = "O_dtprelhi"; break;
case O_dtprello: name = "O_dtprello"; break;
case O_dtprel: name = "O_dtprel"; break;
case O_gottprel: name = "O_gottprel"; break;
case O_tprelhi: name = "O_tprelhi"; break;
case O_tprello: name = "O_tprello"; break;
case O_tprel: name = "O_tprel"; break;
}
fprintf (stderr, ", %s(%s, %s, %d)", name,
(t->X_add_symbol) ? S_GET_NAME (t->X_add_symbol) : "--",
(t->X_op_symbol) ? S_GET_NAME (t->X_op_symbol) : "--",
(int) t->X_add_number);
}
fprintf (stderr, "\n");
fflush (stderr);
}
#endif
static int
tokenize_arguments (str, tok, ntok)
char *str;
expressionS tok[];
int ntok;
{
expressionS *end_tok = tok + ntok;
char *old_input_line_pointer;
int saw_comma = 0, saw_arg = 0;
#ifdef DEBUG_ALPHA
expressionS *orig_tok = tok;
#endif
#ifdef RELOC_OP_P
char *p;
const struct alpha_reloc_op_tag *r;
int c, i;
size_t len;
int reloc_found_p = 0;
#endif
memset (tok, 0, sizeof (*tok) * ntok);
old_input_line_pointer = input_line_pointer;
input_line_pointer = str;
#ifdef RELOC_OP_P
is_end_of_line[(unsigned char) '!'] = 1;
#endif
while (tok < end_tok && *input_line_pointer)
{
SKIP_WHITESPACE ();
switch (*input_line_pointer)
{
case '\0':
goto fini;
#ifdef RELOC_OP_P
case '!':
if (reloc_found_p)
{
as_bad (_("More than one relocation op per insn"));
goto err_report;
}
if (!saw_arg)
goto err;
++input_line_pointer;
SKIP_WHITESPACE ();
p = input_line_pointer;
c = get_symbol_end ();
len = input_line_pointer - p;
if (len == 0)
{
as_bad (_("No relocation operand"));
goto err_report;
}
r = &alpha_reloc_op[0];
for (i = alpha_num_reloc_op - 1; i >= 0; i--, r++)
if (len == r->length && memcmp (p, r->name, len) == 0)
break;
if (i < 0)
{
as_bad (_("Unknown relocation operand: !%s"), p);
goto err_report;
}
*input_line_pointer = c;
SKIP_WHITESPACE ();
if (*input_line_pointer != '!')
{
if (r->require_seq)
{
as_bad (_("no sequence number after !%s"), p);
goto err_report;
}
tok->X_add_number = 0;
}
else
{
if (! r->allow_seq)
{
as_bad (_("!%s does not use a sequence number"), p);
goto err_report;
}
input_line_pointer++;
expression (tok);
if (tok->X_op != O_constant || tok->X_add_number <= 0)
{
as_bad (_("Bad sequence number: !%s!%s"),
r->name, input_line_pointer);
goto err_report;
}
}
tok->X_op = r->op;
reloc_found_p = 1;
++tok;
break;
#endif
case ',':
++input_line_pointer;
if (saw_comma || !saw_arg)
goto err;
saw_comma = 1;
break;
case '(':
{
char *hold = input_line_pointer++;
expression (tok);
if (*input_line_pointer == ')' && tok->X_op == O_register)
{
tok->X_op = (saw_comma ? O_cpregister : O_pregister);
saw_comma = 0;
saw_arg = 1;
++input_line_pointer;
++tok;
break;
}
input_line_pointer = hold;
}
default:
if (saw_arg && !saw_comma)
goto err;
expression (tok);
if (tok->X_op == O_illegal || tok->X_op == O_absent)
goto err;
saw_comma = 0;
saw_arg = 1;
++tok;
break;
}
}
fini:
if (saw_comma)
goto err;
input_line_pointer = old_input_line_pointer;
#ifdef DEBUG_ALPHA
debug_exp (orig_tok, ntok - (end_tok - tok));
#endif
#ifdef RELOC_OP_P
is_end_of_line[(unsigned char) '!'] = 0;
#endif
return ntok - (end_tok - tok);
err:
#ifdef RELOC_OP_P
is_end_of_line[(unsigned char) '!'] = 0;
#endif
input_line_pointer = old_input_line_pointer;
return TOKENIZE_ERROR;
#ifdef RELOC_OP_P
err_report:
is_end_of_line[(unsigned char) '!'] = 0;
#endif
input_line_pointer = old_input_line_pointer;
return TOKENIZE_ERROR_REPORT;
}
static const struct alpha_opcode *
find_opcode_match (first_opcode, tok, pntok, pcpumatch)
const struct alpha_opcode *first_opcode;
const expressionS *tok;
int *pntok;
int *pcpumatch;
{
const struct alpha_opcode *opcode = first_opcode;
int ntok = *pntok;
int got_cpu_match = 0;
do
{
const unsigned char *opidx;
int tokidx = 0;
if (!(opcode->flags & alpha_target))
goto match_failed;
got_cpu_match = 1;
for (opidx = opcode->operands; *opidx; ++opidx)
{
const struct alpha_operand *operand = &alpha_operands[*opidx];
if (operand->flags & AXP_OPERAND_FAKE)
continue;
if (tokidx >= ntok)
{
if ((operand->flags & AXP_OPERAND_OPTIONAL_MASK) == 0)
goto match_failed;
continue;
}
switch (operand->flags & AXP_OPERAND_TYPECHECK_MASK)
{
case AXP_OPERAND_IR:
if (tok[tokidx].X_op != O_register
|| !is_ir_num (tok[tokidx].X_add_number))
goto match_failed;
break;
case AXP_OPERAND_FPR:
if (tok[tokidx].X_op != O_register
|| !is_fpr_num (tok[tokidx].X_add_number))
goto match_failed;
break;
case AXP_OPERAND_IR | AXP_OPERAND_PARENS:
if (tok[tokidx].X_op != O_pregister
|| !is_ir_num (tok[tokidx].X_add_number))
goto match_failed;
break;
case AXP_OPERAND_IR | AXP_OPERAND_PARENS | AXP_OPERAND_COMMA:
if (tok[tokidx].X_op != O_cpregister
|| !is_ir_num (tok[tokidx].X_add_number))
goto match_failed;
break;
case AXP_OPERAND_RELATIVE:
case AXP_OPERAND_SIGNED:
case AXP_OPERAND_UNSIGNED:
switch (tok[tokidx].X_op)
{
case O_illegal:
case O_absent:
case O_register:
case O_pregister:
case O_cpregister:
goto match_failed;
default:
break;
}
break;
default:
abort ();
}
++tokidx;
}
if (tokidx == ntok)
{
*pntok = ntok;
return opcode;
}
match_failed:;
}
while (++opcode - alpha_opcodes < (int) alpha_num_opcodes
&& !strcmp (opcode->name, first_opcode->name));
if (*pcpumatch)
*pcpumatch = got_cpu_match;
return NULL;
}
static const struct alpha_macro *
find_macro_match (first_macro, tok, pntok)
const struct alpha_macro *first_macro;
const expressionS *tok;
int *pntok;
{
const struct alpha_macro *macro = first_macro;
int ntok = *pntok;
do
{
const enum alpha_macro_arg *arg = macro->argsets;
int tokidx = 0;
while (*arg)
{
switch (*arg)
{
case MACRO_EOA:
if (tokidx == ntok)
return macro;
else
tokidx = 0;
break;
case MACRO_IR:
if (tokidx >= ntok || tok[tokidx].X_op != O_register
|| !is_ir_num (tok[tokidx].X_add_number))
goto match_failed;
++tokidx;
break;
case MACRO_PIR:
if (tokidx >= ntok || tok[tokidx].X_op != O_pregister
|| !is_ir_num (tok[tokidx].X_add_number))
goto match_failed;
++tokidx;
break;
case MACRO_OPIR:
if (tokidx < ntok && tok[tokidx].X_op == O_pregister
&& is_ir_num (tok[tokidx].X_add_number))
++tokidx;
break;
case MACRO_CPIR:
if (tokidx >= ntok || tok[tokidx].X_op != O_cpregister
|| !is_ir_num (tok[tokidx].X_add_number))
goto match_failed;
++tokidx;
break;
case MACRO_FPR:
if (tokidx >= ntok || tok[tokidx].X_op != O_register
|| !is_fpr_num (tok[tokidx].X_add_number))
goto match_failed;
++tokidx;
break;
case MACRO_EXP:
if (tokidx >= ntok)
goto match_failed;
switch (tok[tokidx].X_op)
{
case O_illegal:
case O_absent:
case O_register:
case O_pregister:
case O_cpregister:
case O_literal:
case O_lituse_base:
case O_lituse_bytoff:
case O_lituse_jsr:
case O_gpdisp:
case O_gprelhigh:
case O_gprellow:
case O_gprel:
case O_samegp:
goto match_failed;
default:
break;
}
++tokidx;
break;
match_failed:
while (*arg != MACRO_EOA)
++arg;
tokidx = 0;
break;
}
++arg;
}
}
while (++macro - alpha_macros < (int) alpha_num_macros
&& !strcmp (macro->name, first_macro->name));
return NULL;
}
static unsigned
insert_operand (insn, operand, val, file, line)
unsigned insn;
const struct alpha_operand *operand;
offsetT val;
char *file;
unsigned line;
{
if (operand->bits != 32 && !(operand->flags & AXP_OPERAND_NOOVERFLOW))
{
offsetT min, max;
if (operand->flags & AXP_OPERAND_SIGNED)
{
max = (1 << (operand->bits - 1)) - 1;
min = -(1 << (operand->bits - 1));
}
else
{
max = (1 << operand->bits) - 1;
min = 0;
}
if (val < min || val > max)
as_warn_value_out_of_range (_("operand"), val, min, max, file, line);
}
if (operand->insert)
{
const char *errmsg = NULL;
insn = (*operand->insert) (insn, val, &errmsg);
if (errmsg)
as_warn (errmsg);
}
else
insn |= ((val & ((1 << operand->bits) - 1)) << operand->shift);
return insn;
}
static void
assemble_insn (opcode, tok, ntok, insn, reloc)
const struct alpha_opcode *opcode;
const expressionS *tok;
int ntok;
struct alpha_insn *insn;
bfd_reloc_code_real_type reloc;
{
const struct alpha_operand *reloc_operand = NULL;
const expressionS *reloc_exp = NULL;
const unsigned char *argidx;
unsigned image;
int tokidx = 0;
memset (insn, 0, sizeof (*insn));
image = opcode->opcode;
for (argidx = opcode->operands; *argidx; ++argidx)
{
const struct alpha_operand *operand = &alpha_operands[*argidx];
const expressionS *t = (const expressionS *) 0;
if (operand->flags & AXP_OPERAND_FAKE)
{
image = insert_operand (image, operand, 0, NULL, 0);
continue;
}
if (tokidx >= ntok)
{
switch (operand->flags & AXP_OPERAND_OPTIONAL_MASK)
{
case AXP_OPERAND_DEFAULT_FIRST:
t = &tok[0];
break;
case AXP_OPERAND_DEFAULT_SECOND:
t = &tok[1];
break;
case AXP_OPERAND_DEFAULT_ZERO:
{
static expressionS zero_exp;
t = &zero_exp;
zero_exp.X_op = O_constant;
zero_exp.X_unsigned = 1;
}
break;
default:
abort ();
}
}
else
t = &tok[tokidx++];
switch (t->X_op)
{
case O_register:
case O_pregister:
case O_cpregister:
image = insert_operand (image, operand, regno (t->X_add_number),
NULL, 0);
break;
case O_constant:
image = insert_operand (image, operand, t->X_add_number, NULL, 0);
assert (reloc_operand == NULL);
reloc_operand = operand;
reloc_exp = t;
break;
default:
if (operand->default_reloc == 0)
abort ();
if (operand->default_reloc == BFD_RELOC_ALPHA_HINT)
{
struct alpha_fixup *fixup;
if (insn->nfixups >= MAX_INSN_FIXUPS)
as_fatal (_("too many fixups"));
fixup = &insn->fixups[insn->nfixups++];
fixup->exp = *t;
fixup->reloc = BFD_RELOC_ALPHA_HINT;
}
else
{
if (reloc == BFD_RELOC_UNUSED)
reloc = operand->default_reloc;
assert (reloc_operand == NULL);
reloc_operand = operand;
reloc_exp = t;
}
break;
}
}
if (reloc != BFD_RELOC_UNUSED)
{
struct alpha_fixup *fixup;
if (insn->nfixups >= MAX_INSN_FIXUPS)
as_fatal (_("too many fixups"));
if (reloc == BFD_RELOC_ALPHA_GPDISP)
{
if (strcmp (opcode->name, "ldah") == 0)
reloc = BFD_RELOC_ALPHA_GPDISP_HI16;
else if (strcmp (opcode->name, "lda") == 0)
reloc = BFD_RELOC_ALPHA_GPDISP_LO16;
else
as_bad (_("invalid relocation for instruction"));
}
else if (reloc < BFD_RELOC_UNUSED)
{
reloc_howto_type *reloc_howto
= bfd_reloc_type_lookup (stdoutput, reloc);
if (reloc_howto->bitsize != reloc_operand->bits)
{
as_bad (_("invalid relocation for field"));
return;
}
}
fixup = &insn->fixups[insn->nfixups++];
if (reloc_exp)
fixup->exp = *reloc_exp;
else
fixup->exp.X_op = O_absent;
fixup->reloc = reloc;
}
insn->insn = image;
}
static void
emit_insn (insn)
struct alpha_insn *insn;
{
char *f;
int i;
if (alpha_auto_align_on && alpha_current_align < 2)
alpha_align (2, (char *) NULL, alpha_insn_label, 0);
if (alpha_current_align > 2)
alpha_current_align = 2;
alpha_insn_label = NULL;
f = frag_more (4);
md_number_to_chars (f, insn->insn, 4);
#ifdef OBJ_ELF
dwarf2_emit_insn (4);
#endif
for (i = 0; i < insn->nfixups; ++i)
{
const struct alpha_operand *operand = (const struct alpha_operand *) 0;
struct alpha_fixup *fixup = &insn->fixups[i];
struct alpha_reloc_tag *info = NULL;
int size, pcrel;
fixS *fixP;
if ((int) fixup->reloc < 0)
{
operand = &alpha_operands[-(int) fixup->reloc];
size = 4;
pcrel = ((operand->flags & AXP_OPERAND_RELATIVE) != 0);
}
else if (fixup->reloc > BFD_RELOC_UNUSED
|| fixup->reloc == BFD_RELOC_ALPHA_GPDISP_HI16
|| fixup->reloc == BFD_RELOC_ALPHA_GPDISP_LO16)
{
size = 2;
pcrel = 0;
}
else
{
reloc_howto_type *reloc_howto
= bfd_reloc_type_lookup (stdoutput, fixup->reloc);
assert (reloc_howto);
size = bfd_get_reloc_size (reloc_howto);
assert (size >= 1 && size <= 4);
pcrel = reloc_howto->pc_relative;
}
fixP = fix_new_exp (frag_now, f - frag_now->fr_literal, size,
&fixup->exp, pcrel, fixup->reloc);
switch (fixup->reloc)
{
case BFD_RELOC_ALPHA_HINT:
case BFD_RELOC_GPREL32:
case BFD_RELOC_GPREL16:
case BFD_RELOC_ALPHA_GPREL_HI16:
case BFD_RELOC_ALPHA_GPREL_LO16:
case BFD_RELOC_ALPHA_GOTDTPREL16:
case BFD_RELOC_ALPHA_DTPREL_HI16:
case BFD_RELOC_ALPHA_DTPREL_LO16:
case BFD_RELOC_ALPHA_DTPREL16:
case BFD_RELOC_ALPHA_GOTTPREL16:
case BFD_RELOC_ALPHA_TPREL_HI16:
case BFD_RELOC_ALPHA_TPREL_LO16:
case BFD_RELOC_ALPHA_TPREL16:
fixP->fx_no_overflow = 1;
break;
case BFD_RELOC_ALPHA_GPDISP_HI16:
fixP->fx_no_overflow = 1;
fixP->fx_addsy = section_symbol (now_seg);
fixP->fx_offset = 0;
info = get_alpha_reloc_tag (insn->sequence);
if (++info->n_master > 1)
as_bad (_("too many ldah insns for !gpdisp!%ld"), insn->sequence);
if (info->segment != now_seg)
as_bad (_("both insns for !gpdisp!%ld must be in the same section"),
insn->sequence);
fixP->tc_fix_data.info = info;
break;
case BFD_RELOC_ALPHA_GPDISP_LO16:
fixP->fx_no_overflow = 1;
info = get_alpha_reloc_tag (insn->sequence);
if (++info->n_slaves > 1)
as_bad (_("too many lda insns for !gpdisp!%ld"), insn->sequence);
if (info->segment != now_seg)
as_bad (_("both insns for !gpdisp!%ld must be in the same section"),
insn->sequence);
fixP->tc_fix_data.info = info;
info->slaves = fixP;
break;
case BFD_RELOC_ALPHA_LITERAL:
case BFD_RELOC_ALPHA_ELF_LITERAL:
fixP->fx_no_overflow = 1;
if (insn->sequence == 0)
break;
info = get_alpha_reloc_tag (insn->sequence);
info->master = fixP;
info->n_master++;
if (info->segment != now_seg)
info->multi_section_p = 1;
fixP->tc_fix_data.info = info;
break;
#ifdef RELOC_OP_P
case DUMMY_RELOC_LITUSE_ADDR:
fixP->fx_offset = LITUSE_ALPHA_ADDR;
goto do_lituse;
case DUMMY_RELOC_LITUSE_BASE:
fixP->fx_offset = LITUSE_ALPHA_BASE;
goto do_lituse;
case DUMMY_RELOC_LITUSE_BYTOFF:
fixP->fx_offset = LITUSE_ALPHA_BYTOFF;
goto do_lituse;
case DUMMY_RELOC_LITUSE_JSR:
fixP->fx_offset = LITUSE_ALPHA_JSR;
goto do_lituse;
case DUMMY_RELOC_LITUSE_TLSGD:
fixP->fx_offset = LITUSE_ALPHA_TLSGD;
goto do_lituse;
case DUMMY_RELOC_LITUSE_TLSLDM:
fixP->fx_offset = LITUSE_ALPHA_TLSLDM;
goto do_lituse;
do_lituse:
fixP->fx_addsy = section_symbol (now_seg);
fixP->fx_r_type = BFD_RELOC_ALPHA_LITUSE;
info = get_alpha_reloc_tag (insn->sequence);
if (fixup->reloc == DUMMY_RELOC_LITUSE_TLSGD)
info->saw_lu_tlsgd = 1;
else if (fixup->reloc == DUMMY_RELOC_LITUSE_TLSLDM)
info->saw_lu_tlsldm = 1;
if (++info->n_slaves > 1)
{
if (info->saw_lu_tlsgd)
as_bad (_("too many lituse insns for !lituse_tlsgd!%ld"),
insn->sequence);
else if (info->saw_lu_tlsldm)
as_bad (_("too many lituse insns for !lituse_tlsldm!%ld"),
insn->sequence);
}
fixP->tc_fix_data.info = info;
fixP->tc_fix_data.next_reloc = info->slaves;
info->slaves = fixP;
if (info->segment != now_seg)
info->multi_section_p = 1;
break;
case BFD_RELOC_ALPHA_TLSGD:
fixP->fx_no_overflow = 1;
if (insn->sequence == 0)
break;
info = get_alpha_reloc_tag (insn->sequence);
if (info->saw_tlsgd)
as_bad (_("duplicate !tlsgd!%ld"), insn->sequence);
else if (info->saw_tlsldm)
as_bad (_("sequence number in use for !tlsldm!%ld"),
insn->sequence);
else
info->saw_tlsgd = 1;
fixP->tc_fix_data.info = info;
break;
case BFD_RELOC_ALPHA_TLSLDM:
fixP->fx_no_overflow = 1;
if (insn->sequence == 0)
break;
info = get_alpha_reloc_tag (insn->sequence);
if (info->saw_tlsldm)
as_bad (_("duplicate !tlsldm!%ld"), insn->sequence);
else if (info->saw_tlsgd)
as_bad (_("sequence number in use for !tlsgd!%ld"),
insn->sequence);
else
info->saw_tlsldm = 1;
fixP->tc_fix_data.info = info;
break;
#endif
default:
if ((int) fixup->reloc < 0)
{
if (operand->flags & AXP_OPERAND_NOOVERFLOW)
fixP->fx_no_overflow = 1;
}
break;
}
}
}
static void
assemble_tokens_to_insn (opname, tok, ntok, insn)
const char *opname;
const expressionS *tok;
int ntok;
struct alpha_insn *insn;
{
const struct alpha_opcode *opcode;
opcode = (const struct alpha_opcode *) hash_find (alpha_opcode_hash, opname);
if (opcode)
{
int cpumatch;
opcode = find_opcode_match (opcode, tok, &ntok, &cpumatch);
if (opcode)
{
assemble_insn (opcode, tok, ntok, insn, BFD_RELOC_UNUSED);
return;
}
else if (cpumatch)
as_bad (_("inappropriate arguments for opcode `%s'"), opname);
else
as_bad (_("opcode `%s' not supported for target %s"), opname,
alpha_target_name);
}
else
as_bad (_("unknown opcode `%s'"), opname);
}
static void
assemble_tokens (opname, tok, ntok, local_macros_on)
const char *opname;
const expressionS *tok;
int ntok;
int local_macros_on;
{
int found_something = 0;
const struct alpha_opcode *opcode;
const struct alpha_macro *macro;
int cpumatch = 1;
bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
#ifdef RELOC_OP_P
if (ntok && USER_RELOC_P (tok[ntok - 1].X_op))
{
reloc = ALPHA_RELOC_TABLE (tok[ntok - 1].X_op)->reloc;
ntok--;
}
else
#endif
if (local_macros_on)
{
macro = ((const struct alpha_macro *)
hash_find (alpha_macro_hash, opname));
if (macro)
{
found_something = 1;
macro = find_macro_match (macro, tok, &ntok);
if (macro)
{
(*macro->emit) (tok, ntok, macro->arg);
return;
}
}
}
opcode = (const struct alpha_opcode *) hash_find (alpha_opcode_hash, opname);
if (opcode)
{
found_something = 1;
opcode = find_opcode_match (opcode, tok, &ntok, &cpumatch);
if (opcode)
{
struct alpha_insn insn;
assemble_insn (opcode, tok, ntok, &insn, reloc);
if (reloc != BFD_RELOC_UNUSED)
insn.sequence = tok[ntok].X_add_number;
emit_insn (&insn);
return;
}
}
if (found_something)
{
if (cpumatch)
as_bad (_("inappropriate arguments for opcode `%s'"), opname);
else
as_bad (_("opcode `%s' not supported for target %s"), opname,
alpha_target_name);
}
else
as_bad (_("unknown opcode `%s'"), opname);
}
static const char * const sextX_op[] = { "sextb", "sextw", "sextl", NULL };
static const char * const insXl_op[] = { "insbl", "inswl", "insll", "insql" };
static const char * const insXh_op[] = { NULL, "inswh", "inslh", "insqh" };
static const char * const extXl_op[] = { "extbl", "extwl", "extll", "extql" };
static const char * const extXh_op[] = { NULL, "extwh", "extlh", "extqh" };
static const char * const mskXl_op[] = { "mskbl", "mskwl", "mskll", "mskql" };
static const char * const mskXh_op[] = { NULL, "mskwh", "msklh", "mskqh" };
static const char * const stX_op[] = { "stb", "stw", "stl", "stq" };
static const char * const ldXu_op[] = { "ldbu", "ldwu", NULL, NULL };
static void
emit_ldgp (tok, ntok, unused)
const expressionS *tok;
int ntok ATTRIBUTE_UNUSED;
const PTR unused ATTRIBUTE_UNUSED;
{
#ifdef OBJ_AOUT
FIXME
#endif
#if defined(OBJ_ECOFF) || defined(OBJ_ELF)
struct alpha_insn insn;
expressionS newtok[3];
expressionS addend;
#ifdef OBJ_ECOFF
if (regno (tok[2].X_add_number) == AXP_REG_PV)
ecoff_set_gp_prolog_size (0);
#endif
newtok[0] = tok[0];
set_tok_const (newtok[1], 0);
newtok[2] = tok[2];
assemble_tokens_to_insn ("ldah", newtok, 3, &insn);
addend = tok[1];
#ifdef OBJ_ECOFF
if (addend.X_op != O_constant)
as_bad (_("can not resolve expression"));
addend.X_op = O_symbol;
addend.X_add_symbol = alpha_gp_symbol;
#endif
insn.nfixups = 1;
insn.fixups[0].exp = addend;
insn.fixups[0].reloc = BFD_RELOC_ALPHA_GPDISP_HI16;
insn.sequence = next_sequence_num;
emit_insn (&insn);
set_tok_preg (newtok[2], tok[0].X_add_number);
assemble_tokens_to_insn ("lda", newtok, 3, &insn);
#ifdef OBJ_ECOFF
addend.X_add_number += 4;
#endif
insn.nfixups = 1;
insn.fixups[0].exp = addend;
insn.fixups[0].reloc = BFD_RELOC_ALPHA_GPDISP_LO16;
insn.sequence = next_sequence_num--;
emit_insn (&insn);
#endif
}
#ifdef OBJ_EVAX
valueT
add_to_link_pool (basesym, sym, addend)
symbolS *basesym;
symbolS *sym;
offsetT addend;
{
segT current_section = now_seg;
int current_subsec = now_subseg;
valueT offset;
bfd_reloc_code_real_type reloc_type;
char *p;
segment_info_type *seginfo = seg_info (alpha_link_section);
fixS *fixp;
offset = - *symbol_get_obj (basesym);
if (seginfo->frchainP)
for (fixp = seginfo->frchainP->fix_root;
fixp != (fixS *) NULL;
fixp = fixp->fx_next, offset += 8)
{
if (fixp->fx_addsy == sym && fixp->fx_offset == addend)
{
if (range_signed_16 (offset))
{
return offset;
}
}
}
subseg_set (alpha_link_section, 0);
p = frag_more (8);
memset (p, 0, 8);
fix_new (frag_now, p - frag_now->fr_literal, 8, sym, addend, 0,
BFD_RELOC_64);
subseg_set (current_section, current_subsec);
seginfo->literal_pool_size += 8;
return offset;
}
#endif
static long
load_expression (targreg, exp, pbasereg, poffset)
int targreg;
const expressionS *exp;
int *pbasereg;
expressionS *poffset;
{
long emit_lituse = 0;
offsetT addend = exp->X_add_number;
int basereg = *pbasereg;
struct alpha_insn insn;
expressionS newtok[3];
switch (exp->X_op)
{
case O_symbol:
{
#ifdef OBJ_ECOFF
offsetT lit;
if (!range_signed_32 (addend) &&
(alpha_noat_on || targreg == AXP_REG_AT))
{
lit = add_to_literal_pool (exp->X_add_symbol, addend,
alpha_lita_section, 8);
addend = 0;
}
else
{
lit = add_to_literal_pool (exp->X_add_symbol, 0,
alpha_lita_section, 8);
}
if (lit >= 0x8000)
as_fatal (_("overflow in literal (.lita) table"));
if (basereg != alpha_gp_register && targreg == basereg)
{
if (alpha_noat_on)
as_bad (_("macro requires $at register while noat in effect"));
if (targreg == AXP_REG_AT)
as_bad (_("macro requires $at while $at in use"));
set_tok_reg (newtok[0], AXP_REG_AT);
}
else
set_tok_reg (newtok[0], targreg);
set_tok_sym (newtok[1], alpha_lita_symbol, lit);
set_tok_preg (newtok[2], alpha_gp_register);
assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
assert (insn.nfixups == 1);
insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL;
insn.sequence = emit_lituse = next_sequence_num--;
#endif
#ifdef OBJ_ELF
if (basereg != alpha_gp_register && targreg == basereg)
{
if (alpha_noat_on)
as_bad (_("macro requires $at register while noat in effect"));
if (targreg == AXP_REG_AT)
as_bad (_("macro requires $at while $at in use"));
set_tok_reg (newtok[0], AXP_REG_AT);
}
else
set_tok_reg (newtok[0], targreg);
if (1
|| (!range_signed_32 (addend)
&& (alpha_noat_on || targreg == AXP_REG_AT)))
{
newtok[1] = *exp;
addend = 0;
}
else
{
set_tok_sym (newtok[1], exp->X_add_symbol, 0);
}
set_tok_preg (newtok[2], alpha_gp_register);
assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
assert (insn.nfixups == 1);
insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL;
insn.sequence = emit_lituse = next_sequence_num--;
#endif
#ifdef OBJ_EVAX
offsetT link;
if (exp->X_add_symbol == alpha_evax_proc.symbol)
{
if (range_signed_16 (addend))
{
set_tok_reg (newtok[0], targreg);
set_tok_const (newtok[1], addend);
set_tok_preg (newtok[2], basereg);
assemble_tokens_to_insn ("lda", newtok, 3, &insn);
addend = 0;
}
else
{
set_tok_reg (newtok[0], targreg);
set_tok_const (newtok[1], 0);
set_tok_preg (newtok[2], basereg);
assemble_tokens_to_insn ("lda", newtok, 3, &insn);
}
}
else
{
if (!range_signed_32 (addend))
{
link = add_to_link_pool (alpha_evax_proc.symbol,
exp->X_add_symbol, addend);
addend = 0;
}
else
{
link = add_to_link_pool (alpha_evax_proc.symbol,
exp->X_add_symbol, 0);
}
set_tok_reg (newtok[0], targreg);
set_tok_const (newtok[1], link);
set_tok_preg (newtok[2], basereg);
assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
}
#endif
emit_insn (&insn);
#ifndef OBJ_EVAX
if (basereg != alpha_gp_register && basereg != AXP_REG_ZERO)
{
set_tok_reg (newtok[1], basereg);
set_tok_reg (newtok[2], targreg);
assemble_tokens ("addq", newtok, 3, 0);
}
#endif
basereg = targreg;
}
break;
case O_constant:
break;
case O_subtract:
set_tok_reg (newtok[0], targreg);
newtok[1] = *exp;
set_tok_preg (newtok[2], basereg);
assemble_tokens ("lda", newtok, 3, 0);
if (poffset)
set_tok_const (*poffset, 0);
return 0;
case O_big:
if (exp->X_add_number > 0)
as_bad (_("bignum invalid; zero assumed"));
else
as_bad (_("floating point number invalid; zero assumed"));
addend = 0;
break;
default:
as_bad (_("can't handle expression"));
addend = 0;
break;
}
if (!range_signed_32 (addend))
{
offsetT lit;
long seq_num = next_sequence_num--;
#ifdef OBJ_EVAX
lit = add_to_link_pool (alpha_evax_proc.symbol,
section_symbol (absolute_section), addend);
set_tok_reg (newtok[0], targreg);
set_tok_const (newtok[1], lit);
set_tok_preg (newtok[2], alpha_gp_register);
assemble_tokens ("ldq", newtok, 3, 0);
#else
if (alpha_lit8_section == NULL)
{
create_literal_section (".lit8",
&alpha_lit8_section,
&alpha_lit8_symbol);
#ifdef OBJ_ECOFF
alpha_lit8_literal = add_to_literal_pool (alpha_lit8_symbol, 0x8000,
alpha_lita_section, 8);
if (alpha_lit8_literal >= 0x8000)
as_fatal (_("overflow in literal (.lita) table"));
#endif
}
lit = add_to_literal_pool (NULL, addend, alpha_lit8_section, 8) - 0x8000;
if (lit >= 0x8000)
as_fatal (_("overflow in literal (.lit8) table"));
if (targreg == basereg)
{
if (alpha_noat_on)
as_bad (_("macro requires $at register while noat in effect"));
if (targreg == AXP_REG_AT)
as_bad (_("macro requires $at while $at in use"));
set_tok_reg (newtok[0], AXP_REG_AT);
}
else
set_tok_reg (newtok[0], targreg);
#ifdef OBJ_ECOFF
set_tok_sym (newtok[1], alpha_lita_symbol, alpha_lit8_literal);
#endif
#ifdef OBJ_ELF
set_tok_sym (newtok[1], alpha_lit8_symbol, 0x8000);
#endif
set_tok_preg (newtok[2], alpha_gp_register);
assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
assert (insn.nfixups == 1);
#ifdef OBJ_ECOFF
insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL;
#endif
#ifdef OBJ_ELF
insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL;
#endif
insn.sequence = seq_num;
emit_insn (&insn);
set_tok_const (newtok[1], lit);
set_tok_preg (newtok[2], newtok[0].X_add_number);
assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
assert (insn.nfixups < MAX_INSN_FIXUPS);
insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
insn.fixups[insn.nfixups].exp.X_op = O_absent;
insn.nfixups++;
insn.sequence = seq_num;
emit_lituse = 0;
emit_insn (&insn);
if (basereg != AXP_REG_ZERO)
{
set_tok_reg (newtok[1], basereg);
set_tok_reg (newtok[2], targreg);
assemble_tokens ("addq", newtok, 3, 0);
}
#endif
if (poffset)
set_tok_const (*poffset, 0);
*pbasereg = targreg;
}
else
{
offsetT low, high, extra, tmp;
low = sign_extend_16 (addend);
tmp = addend - low;
high = sign_extend_16 (tmp >> 16);
if (tmp - (high << 16))
{
extra = 0x4000;
tmp -= 0x40000000;
high = sign_extend_16 (tmp >> 16);
}
else
extra = 0;
set_tok_reg (newtok[0], targreg);
set_tok_preg (newtok[2], basereg);
if (extra)
{
set_tok_const (newtok[1], extra);
assemble_tokens ("ldah", newtok, 3, 0);
set_tok_preg (newtok[2], basereg = targreg);
}
if (high)
{
set_tok_const (newtok[1], high);
assemble_tokens ("ldah", newtok, 3, 0);
basereg = targreg;
set_tok_preg (newtok[2], basereg);
}
if ((low && !poffset) || (!poffset && basereg != targreg))
{
set_tok_const (newtok[1], low);
assemble_tokens ("lda", newtok, 3, 0);
basereg = targreg;
low = 0;
}
if (poffset)
set_tok_const (*poffset, low);
*pbasereg = basereg;
}
return emit_lituse;
}
static void
emit_lda (tok, ntok, unused)
const expressionS *tok;
int ntok;
const PTR unused ATTRIBUTE_UNUSED;
{
int basereg;
if (ntok == 2)
basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register);
else
basereg = tok[2].X_add_number;
(void) load_expression (tok[0].X_add_number, &tok[1], &basereg, NULL);
}
static void
emit_ldah (tok, ntok, unused)
const expressionS *tok;
int ntok ATTRIBUTE_UNUSED;
const PTR unused ATTRIBUTE_UNUSED;
{
expressionS newtok[3];
newtok[0] = tok[0];
newtok[1] = tok[1];
set_tok_preg (newtok[2], AXP_REG_ZERO);
assemble_tokens ("ldah", newtok, 3, 0);
}
static void
emit_ir_load (tok, ntok, opname)
const expressionS *tok;
int ntok;
const PTR opname;
{
int basereg;
long lituse;
expressionS newtok[3];
struct alpha_insn insn;
if (ntok == 2)
basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register);
else
basereg = tok[2].X_add_number;
lituse = load_expression (tok[0].X_add_number, &tok[1], &basereg,
&newtok[1]);
newtok[0] = tok[0];
set_tok_preg (newtok[2], basereg);
assemble_tokens_to_insn ((const char *) opname, newtok, 3, &insn);
if (lituse)
{
assert (insn.nfixups < MAX_INSN_FIXUPS);
insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
insn.fixups[insn.nfixups].exp.X_op = O_absent;
insn.nfixups++;
insn.sequence = lituse;
}
emit_insn (&insn);
}
static void
emit_loadstore (tok, ntok, opname)
const expressionS *tok;
int ntok;
const PTR opname;
{
int basereg;
long lituse;
expressionS newtok[3];
struct alpha_insn insn;
if (ntok == 2)
basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register);
else
basereg = tok[2].X_add_number;
if (tok[1].X_op != O_constant || !range_signed_16 (tok[1].X_add_number))
{
if (alpha_noat_on)
as_bad (_("macro requires $at register while noat in effect"));
lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, &newtok[1]);
}
else
{
newtok[1] = tok[1];
lituse = 0;
}
newtok[0] = tok[0];
set_tok_preg (newtok[2], basereg);
assemble_tokens_to_insn ((const char *) opname, newtok, 3, &insn);
if (lituse)
{
assert (insn.nfixups < MAX_INSN_FIXUPS);
insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
insn.fixups[insn.nfixups].exp.X_op = O_absent;
insn.nfixups++;
insn.sequence = lituse;
}
emit_insn (&insn);
}
static void
emit_ldXu (tok, ntok, vlgsize)
const expressionS *tok;
int ntok;
const PTR vlgsize;
{
if (alpha_target & AXP_OPCODE_BWX)
emit_ir_load (tok, ntok, ldXu_op[(long) vlgsize]);
else
{
expressionS newtok[3];
struct alpha_insn insn;
int basereg;
long lituse;
if (alpha_noat_on)
as_bad (_("macro requires $at register while noat in effect"));
if (ntok == 2)
basereg = (tok[1].X_op == O_constant
? AXP_REG_ZERO : alpha_gp_register);
else
basereg = tok[2].X_add_number;
lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL);
newtok[0] = tok[0];
set_tok_const (newtok[1], 0);
set_tok_preg (newtok[2], basereg);
assemble_tokens_to_insn ("ldq_u", newtok, 3, &insn);
if (lituse)
{
assert (insn.nfixups < MAX_INSN_FIXUPS);
insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
insn.fixups[insn.nfixups].exp.X_op = O_absent;
insn.nfixups++;
insn.sequence = lituse;
}
emit_insn (&insn);
set_tok_reg (newtok[1], basereg);
newtok[2] = newtok[0];
assemble_tokens_to_insn (extXl_op[(long) vlgsize], newtok, 3, &insn);
if (lituse)
{
assert (insn.nfixups < MAX_INSN_FIXUPS);
insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BYTOFF;
insn.fixups[insn.nfixups].exp.X_op = O_absent;
insn.nfixups++;
insn.sequence = lituse;
}
emit_insn (&insn);
}
}
static void
emit_ldX (tok, ntok, vlgsize)
const expressionS *tok;
int ntok;
const PTR vlgsize;
{
emit_ldXu (tok, ntok, vlgsize);
assemble_tokens (sextX_op[(long) vlgsize], tok, 1, 1);
}
static void
emit_uldXu (tok, ntok, vlgsize)
const expressionS *tok;
int ntok;
const PTR vlgsize;
{
long lgsize = (long) vlgsize;
expressionS newtok[3];
if (alpha_noat_on)
as_bad (_("macro requires $at register while noat in effect"));
memcpy (newtok, tok, sizeof (expressionS) * ntok);
newtok[0].X_add_number = AXP_REG_AT;
assemble_tokens ("lda", newtok, ntok, 1);
set_tok_reg (newtok[0], AXP_REG_T9);
set_tok_const (newtok[1], 0);
set_tok_preg (newtok[2], AXP_REG_AT);
assemble_tokens ("ldq_u", newtok, 3, 1);
set_tok_reg (newtok[0], AXP_REG_T10);
set_tok_const (newtok[1], (1 << lgsize) - 1);
assemble_tokens ("ldq_u", newtok, 3, 1);
set_tok_reg (newtok[0], AXP_REG_T9);
set_tok_reg (newtok[1], AXP_REG_AT);
set_tok_reg (newtok[2], AXP_REG_T9);
assemble_tokens (extXl_op[lgsize], newtok, 3, 1);
set_tok_reg (newtok[0], AXP_REG_T10);
set_tok_reg (newtok[2], AXP_REG_T10);
assemble_tokens (extXh_op[lgsize], newtok, 3, 1);
set_tok_reg (newtok[0], AXP_REG_T9);
set_tok_reg (newtok[1], AXP_REG_T10);
newtok[2] = tok[0];
assemble_tokens ("or", newtok, 3, 1);
}
static void
emit_uldX (tok, ntok, vlgsize)
const expressionS *tok;
int ntok;
const PTR vlgsize;
{
emit_uldXu (tok, ntok, vlgsize);
assemble_tokens (sextX_op[(long) vlgsize], tok, 1, 1);
}
static void
emit_ldil (tok, ntok, unused)
const expressionS *tok;
int ntok;
const PTR unused ATTRIBUTE_UNUSED;
{
expressionS newtok[2];
memcpy (newtok, tok, sizeof (newtok));
newtok[1].X_add_number = sign_extend_32 (tok[1].X_add_number);
assemble_tokens ("lda", newtok, ntok, 1);
}
static void
emit_stX (tok, ntok, vlgsize)
const expressionS *tok;
int ntok;
const PTR vlgsize;
{
int lgsize = (int) (long) vlgsize;
if (alpha_target & AXP_OPCODE_BWX)
emit_loadstore (tok, ntok, stX_op[lgsize]);
else
{
expressionS newtok[3];
struct alpha_insn insn;
int basereg;
long lituse;
if (alpha_noat_on)
as_bad (_("macro requires $at register while noat in effect"));
if (ntok == 2)
basereg = (tok[1].X_op == O_constant
? AXP_REG_ZERO : alpha_gp_register);
else
basereg = tok[2].X_add_number;
lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL);
set_tok_reg (newtok[0], AXP_REG_T9);
set_tok_const (newtok[1], 0);
set_tok_preg (newtok[2], basereg);
assemble_tokens_to_insn ("ldq_u", newtok, 3, &insn);
if (lituse)
{
assert (insn.nfixups < MAX_INSN_FIXUPS);
insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
insn.fixups[insn.nfixups].exp.X_op = O_absent;
insn.nfixups++;
insn.sequence = lituse;
}
emit_insn (&insn);
newtok[0] = tok[0];
set_tok_reg (newtok[1], basereg);
set_tok_reg (newtok[2], AXP_REG_T10);
assemble_tokens_to_insn (insXl_op[lgsize], newtok, 3, &insn);
if (lituse)
{
assert (insn.nfixups < MAX_INSN_FIXUPS);
insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BYTOFF;
insn.fixups[insn.nfixups].exp.X_op = O_absent;
insn.nfixups++;
insn.sequence = lituse;
}
emit_insn (&insn);
set_tok_reg (newtok[0], AXP_REG_T9);
newtok[2] = newtok[0];
assemble_tokens_to_insn (mskXl_op[lgsize], newtok, 3, &insn);
if (lituse)
{
assert (insn.nfixups < MAX_INSN_FIXUPS);
insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BYTOFF;
insn.fixups[insn.nfixups].exp.X_op = O_absent;
insn.nfixups++;
insn.sequence = lituse;
}
emit_insn (&insn);
set_tok_reg (newtok[1], AXP_REG_T10);
assemble_tokens ("or", newtok, 3, 1);
set_tok_const(newtok[1], 0);
set_tok_preg (newtok[2], AXP_REG_AT);
assemble_tokens_to_insn ("stq_u", newtok, 3, &insn);
if (lituse)
{
assert (insn.nfixups < MAX_INSN_FIXUPS);
insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
insn.fixups[insn.nfixups].exp.X_op = O_absent;
insn.nfixups++;
insn.sequence = lituse;
}
emit_insn (&insn);
}
}
static void
emit_ustX (tok, ntok, vlgsize)
const expressionS *tok;
int ntok;
const PTR vlgsize;
{
int lgsize = (int) (long) vlgsize;
expressionS newtok[3];
memcpy (newtok, tok, sizeof (expressionS) * ntok);
newtok[0].X_add_number = AXP_REG_AT;
assemble_tokens ("lda", newtok, ntok, 1);
set_tok_reg (newtok[0], AXP_REG_T9);
set_tok_const (newtok[1], 0);
set_tok_preg (newtok[2], AXP_REG_AT);
assemble_tokens ("ldq_u", newtok, 3, 1);
set_tok_reg (newtok[0], AXP_REG_T10);
set_tok_const (newtok[1], (1 << lgsize) - 1);
assemble_tokens ("ldq_u", newtok, 3, 1);
newtok[0] = tok[0];
set_tok_reg (newtok[1], AXP_REG_AT);
set_tok_reg (newtok[2], AXP_REG_T11);
assemble_tokens (insXl_op[lgsize], newtok, 3, 1);
set_tok_reg (newtok[2], AXP_REG_T12);
assemble_tokens (insXh_op[lgsize], newtok, 3, 1);
set_tok_reg (newtok[0], AXP_REG_T9);
newtok[2] = newtok[0];
assemble_tokens (mskXl_op[lgsize], newtok, 3, 1);
set_tok_reg (newtok[0], AXP_REG_T10);
newtok[2] = newtok[0];
assemble_tokens (mskXh_op[lgsize], newtok, 3, 1);
set_tok_reg (newtok[0], AXP_REG_T9);
set_tok_reg (newtok[1], AXP_REG_T11);
newtok[2] = newtok[0];
assemble_tokens ("or", newtok, 3, 1);
set_tok_reg (newtok[0], AXP_REG_T10);
set_tok_reg (newtok[1], AXP_REG_T12);
newtok[2] = newtok[0];
assemble_tokens ("or", newtok, 3, 1);
set_tok_reg (newtok[0], AXP_REG_T9);
set_tok_const (newtok[1], 0);
set_tok_preg (newtok[2], AXP_REG_AT);
assemble_tokens ("stq_u", newtok, 3, 1);
set_tok_reg (newtok[0], AXP_REG_T10);
set_tok_const (newtok[1], (1 << lgsize) - 1);
assemble_tokens ("stq_u", newtok, 3, 1);
}
static void
emit_sextX (tok, ntok, vlgsize)
const expressionS *tok;
int ntok;
const PTR vlgsize;
{
long lgsize = (long) vlgsize;
if (alpha_target & AXP_OPCODE_BWX)
assemble_tokens (sextX_op[lgsize], tok, ntok, 0);
else
{
int bitshift = 64 - 8 * (1 << lgsize);
expressionS newtok[3];
newtok[0] = tok[0];
set_tok_const (newtok[1], bitshift);
newtok[2] = tok[ntok - 1];
assemble_tokens ("sll", newtok, 3, 1);
newtok[0] = newtok[2];
assemble_tokens ("sra", newtok, 3, 1);
}
}
#ifdef OBJ_EVAX
static void
emit_division (tok, ntok, symname)
const expressionS *tok;
int ntok;
const PTR symname;
{
int xr, yr, rr;
symbolS *sym;
expressionS newtok[3];
xr = regno (tok[0].X_add_number);
yr = regno (tok[1].X_add_number);
if (ntok < 3)
rr = xr;
else
rr = regno (tok[2].X_add_number);
if (yr == AXP_REG_R16 && xr == AXP_REG_R17)
{
if (alpha_noat_on)
as_bad (_("macro requires $at register while noat in effect"));
set_tok_reg (newtok[0], AXP_REG_R16);
set_tok_reg (newtok[1], AXP_REG_AT);
assemble_tokens ("mov", newtok, 2, 1);
set_tok_reg (newtok[0], AXP_REG_R17);
set_tok_reg (newtok[1], AXP_REG_R16);
assemble_tokens ("mov", newtok, 2, 1);
set_tok_reg (newtok[0], AXP_REG_AT);
set_tok_reg (newtok[1], AXP_REG_R17);
assemble_tokens ("mov", newtok, 2, 1);
}
else
{
if (yr == AXP_REG_R16)
{
set_tok_reg (newtok[0], AXP_REG_R16);
set_tok_reg (newtok[1], AXP_REG_R17);
assemble_tokens ("mov", newtok, 2, 1);
}
if (xr != AXP_REG_R16)
{
set_tok_reg (newtok[0], xr);
set_tok_reg (newtok[1], AXP_REG_R16);
assemble_tokens ("mov", newtok, 2, 1);
}
if (yr != AXP_REG_R16 && yr != AXP_REG_R17)
{
set_tok_reg (newtok[0], yr);
set_tok_reg (newtok[1], AXP_REG_R17);
assemble_tokens ("mov", newtok, 2, 1);
}
}
sym = symbol_find_or_make ((const char *) symname);
set_tok_reg (newtok[0], AXP_REG_AT);
set_tok_sym (newtok[1], sym, 0);
assemble_tokens ("lda", newtok, 2, 1);
set_tok_reg (newtok[0], AXP_REG_AT);
set_tok_cpreg (newtok[1], AXP_REG_AT);
set_tok_const (newtok[2], 0);
assemble_tokens ("jsr", newtok, 3, 1);
if (rr != AXP_REG_R0)
{
set_tok_reg (newtok[0], AXP_REG_R0);
set_tok_reg (newtok[1], rr);
assemble_tokens ("mov", newtok, 2, 1);
}
}
#else
static void
emit_division (tok, ntok, symname)
const expressionS *tok;
int ntok;
const PTR symname;
{
int xr, yr, rr;
symbolS *sym;
expressionS newtok[3];
xr = regno (tok[0].X_add_number);
yr = regno (tok[1].X_add_number);
if (ntok < 3)
rr = xr;
else
rr = regno (tok[2].X_add_number);
sym = symbol_find_or_make ((const char *) symname);
if (yr == AXP_REG_T10 && xr == AXP_REG_T11)
{
if (alpha_noat_on)
as_bad (_("macro requires $at register while noat in effect"));
set_tok_reg (newtok[0], AXP_REG_T10);
set_tok_reg (newtok[1], AXP_REG_AT);
assemble_tokens ("mov", newtok, 2, 1);
set_tok_reg (newtok[0], AXP_REG_T11);
set_tok_reg (newtok[1], AXP_REG_T10);
assemble_tokens ("mov", newtok, 2, 1);
set_tok_reg (newtok[0], AXP_REG_AT);
set_tok_reg (newtok[1], AXP_REG_T11);
assemble_tokens ("mov", newtok, 2, 1);
}
else
{
if (yr == AXP_REG_T10)
{
set_tok_reg (newtok[0], AXP_REG_T10);
set_tok_reg (newtok[1], AXP_REG_T11);
assemble_tokens ("mov", newtok, 2, 1);
}
if (xr != AXP_REG_T10)
{
set_tok_reg (newtok[0], xr);
set_tok_reg (newtok[1], AXP_REG_T10);
assemble_tokens ("mov", newtok, 2, 1);
}
if (yr != AXP_REG_T10 && yr != AXP_REG_T11)
{
set_tok_reg (newtok[0], yr);
set_tok_reg (newtok[1], AXP_REG_T11);
assemble_tokens ("mov", newtok, 2, 1);
}
}
set_tok_reg (newtok[0], AXP_REG_T9);
set_tok_sym (newtok[1], sym, 0);
assemble_tokens ("jsr", newtok, 2, 1);
#ifdef OBJ_AOUT
FIXME
#endif
#if defined(OBJ_ECOFF) || defined(OBJ_ELF)
set_tok_reg (newtok[0], alpha_gp_register);
set_tok_const (newtok[1], 0);
set_tok_preg (newtok[2], AXP_REG_T9);
assemble_tokens ("ldgp", newtok, 3, 1);
#endif
if (rr != AXP_REG_T12)
{
set_tok_reg (newtok[0], AXP_REG_T12);
set_tok_reg (newtok[1], rr);
assemble_tokens ("mov", newtok, 2, 1);
}
}
#endif
static void
emit_jsrjmp (tok, ntok, vopname)
const expressionS *tok;
int ntok;
const PTR vopname;
{
const char *opname = (const char *) vopname;
struct alpha_insn insn;
expressionS newtok[3];
int r, tokidx = 0;
long lituse = 0;
if (tokidx < ntok && tok[tokidx].X_op == O_register)
r = regno (tok[tokidx++].X_add_number);
else
r = strcmp (opname, "jmp") == 0 ? AXP_REG_ZERO : AXP_REG_RA;
set_tok_reg (newtok[0], r);
if (tokidx < ntok &&
(tok[tokidx].X_op == O_pregister || tok[tokidx].X_op == O_cpregister))
r = regno (tok[tokidx++].X_add_number);
#ifdef OBJ_EVAX
#else
else
{
int basereg = alpha_gp_register;
lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], &basereg, NULL);
}
#endif
set_tok_cpreg (newtok[1], r);
#ifdef OBJ_EVAX
#else
if (tokidx < ntok)
newtok[2] = tok[tokidx];
else
#endif
set_tok_const (newtok[2], 0);
assemble_tokens_to_insn (opname, newtok, 3, &insn);
if (lituse)
{
assert (insn.nfixups < MAX_INSN_FIXUPS);
insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_JSR;
insn.fixups[insn.nfixups].exp.X_op = O_absent;
insn.nfixups++;
insn.sequence = lituse;
}
emit_insn (&insn);
}
static void
emit_retjcr (tok, ntok, vopname)
const expressionS *tok;
int ntok;
const PTR vopname;
{
const char *opname = (const char *) vopname;
expressionS newtok[3];
int r, tokidx = 0;
if (tokidx < ntok && tok[tokidx].X_op == O_register)
r = regno (tok[tokidx++].X_add_number);
else
r = AXP_REG_ZERO;
set_tok_reg (newtok[0], r);
if (tokidx < ntok &&
(tok[tokidx].X_op == O_pregister || tok[tokidx].X_op == O_cpregister))
r = regno (tok[tokidx++].X_add_number);
else
r = AXP_REG_RA;
set_tok_cpreg (newtok[1], r);
if (tokidx < ntok)
newtok[2] = tok[tokidx];
else
set_tok_const (newtok[2], strcmp (opname, "ret") == 0);
assemble_tokens (opname, newtok, 3, 0);
}
static void
s_alpha_text (i)
int i;
{
#ifdef OBJ_ELF
obj_elf_text (i);
#else
s_text (i);
#endif
alpha_insn_label = NULL;
alpha_auto_align_on = 1;
alpha_current_align = 0;
}
static void
s_alpha_data (i)
int i;
{
#ifdef OBJ_ELF
obj_elf_data (i);
#else
s_data (i);
#endif
alpha_insn_label = NULL;
alpha_auto_align_on = 1;
alpha_current_align = 0;
}
#if defined (OBJ_ECOFF) || defined (OBJ_EVAX)
static void
s_alpha_comm (ignore)
int ignore ATTRIBUTE_UNUSED;
{
register char *name;
register char c;
register char *p;
offsetT temp;
register symbolS *symbolP;
#ifdef OBJ_EVAX
segT current_section = now_seg;
int current_subsec = now_subseg;
segT new_seg;
#endif
name = input_line_pointer;
c = get_symbol_end ();
p = input_line_pointer;
*p = c;
SKIP_WHITESPACE ();
if (*input_line_pointer == ',')
{
input_line_pointer++;
SKIP_WHITESPACE ();
}
if ((temp = get_absolute_expression ()) < 0)
{
as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) temp);
ignore_rest_of_line ();
return;
}
*p = 0;
symbolP = symbol_find_or_make (name);
#ifdef OBJ_EVAX
new_seg = subseg_new (xstrdup (name), 0);
#endif
*p = c;
#ifdef OBJ_EVAX
if (*input_line_pointer == ',')
{
offsetT align;
input_line_pointer++;
align = get_absolute_expression ();
bfd_set_section_alignment (stdoutput, new_seg, align);
}
#endif
if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
{
as_bad (_("Ignoring attempt to re-define symbol"));
ignore_rest_of_line ();
return;
}
#ifdef OBJ_EVAX
if (bfd_section_size (stdoutput, new_seg) > 0)
{
if (bfd_section_size (stdoutput, new_seg) != temp)
as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."),
S_GET_NAME (symbolP),
(long) bfd_section_size (stdoutput, new_seg),
(long) temp);
}
#else
if (S_GET_VALUE (symbolP))
{
if (S_GET_VALUE (symbolP) != (valueT) temp)
as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."),
S_GET_NAME (symbolP),
(long) S_GET_VALUE (symbolP),
(long) temp);
}
#endif
else
{
#ifdef OBJ_EVAX
subseg_set (new_seg, 0);
p = frag_more (temp);
new_seg->flags |= SEC_IS_COMMON;
if (! S_IS_DEFINED (symbolP))
S_SET_SEGMENT (symbolP, new_seg);
#else
S_SET_VALUE (symbolP, (valueT) temp);
#endif
S_SET_EXTERNAL (symbolP);
}
#ifdef OBJ_EVAX
subseg_set (current_section, current_subsec);
#endif
know (symbol_get_frag (symbolP) == &zero_address_frag);
demand_empty_rest_of_line ();
}
#endif
#ifdef OBJ_ECOFF
static void
s_alpha_rdata (ignore)
int ignore ATTRIBUTE_UNUSED;
{
int temp;
temp = get_absolute_expression ();
subseg_new (".rdata", 0);
demand_empty_rest_of_line ();
alpha_insn_label = NULL;
alpha_auto_align_on = 1;
alpha_current_align = 0;
}
#endif
#ifdef OBJ_ECOFF
static void
s_alpha_sdata (ignore)
int ignore ATTRIBUTE_UNUSED;
{
int temp;
temp = get_absolute_expression ();
subseg_new (".sdata", 0);
demand_empty_rest_of_line ();
alpha_insn_label = NULL;
alpha_auto_align_on = 1;
alpha_current_align = 0;
}
#endif
#ifdef OBJ_ELF
struct alpha_elf_frame_data
{
symbolS *func_sym;
symbolS *func_end_sym;
symbolS *prologue_sym;
unsigned int mask;
unsigned int fmask;
int fp_regno;
int ra_regno;
offsetT frame_size;
offsetT mask_offset;
offsetT fmask_offset;
struct alpha_elf_frame_data *next;
};
static struct alpha_elf_frame_data *all_frame_data;
static struct alpha_elf_frame_data **plast_frame_data = &all_frame_data;
static struct alpha_elf_frame_data *cur_frame_data;
static void
s_alpha_section (ignore)
int ignore ATTRIBUTE_UNUSED;
{
obj_elf_section (ignore);
alpha_insn_label = NULL;
alpha_auto_align_on = 1;
alpha_current_align = 0;
}
static void
s_alpha_ent (dummy)
int dummy ATTRIBUTE_UNUSED;
{
if (ECOFF_DEBUGGING)
ecoff_directive_ent (0);
else
{
char *name, name_end;
name = input_line_pointer;
name_end = get_symbol_end ();
if (! is_name_beginner (*name))
{
as_warn (_(".ent directive has no name"));
*input_line_pointer = name_end;
}
else
{
symbolS *sym;
if (cur_frame_data)
as_warn (_("nested .ent directives"));
sym = symbol_find_or_make (name);
symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
cur_frame_data = calloc (1, sizeof (*cur_frame_data));
cur_frame_data->func_sym = sym;
cur_frame_data->fp_regno = 30;
cur_frame_data->ra_regno = 26;
*plast_frame_data = cur_frame_data;
plast_frame_data = &cur_frame_data->next;
*input_line_pointer = name_end;
SKIP_WHITESPACE ();
if (*input_line_pointer == ',')
{
input_line_pointer++;
SKIP_WHITESPACE ();
}
if (ISDIGIT (*input_line_pointer) || *input_line_pointer == '-')
(void) get_absolute_expression ();
}
demand_empty_rest_of_line ();
}
}
static void
s_alpha_end (dummy)
int dummy ATTRIBUTE_UNUSED;
{
if (ECOFF_DEBUGGING)
ecoff_directive_end (0);
else
{
char *name, name_end;
name = input_line_pointer;
name_end = get_symbol_end ();
if (! is_name_beginner (*name))
{
as_warn (_(".end directive has no name"));
*input_line_pointer = name_end;
}
else
{
symbolS *sym;
sym = symbol_find (name);
if (!cur_frame_data)
as_warn (_(".end directive without matching .ent"));
else if (sym != cur_frame_data->func_sym)
as_warn (_(".end directive names different symbol than .ent"));
if (sym && cur_frame_data)
{
OBJ_SYMFIELD_TYPE *obj = symbol_get_obj (sym);
expressionS *exp = xmalloc (sizeof (expressionS));
obj->size = exp;
exp->X_op = O_subtract;
exp->X_add_symbol = symbol_temp_new_now ();
exp->X_op_symbol = sym;
exp->X_add_number = 0;
cur_frame_data->func_end_sym = exp->X_add_symbol;
}
cur_frame_data = NULL;
*input_line_pointer = name_end;
}
demand_empty_rest_of_line ();
}
}
static void
s_alpha_mask (fp)
int fp;
{
if (ECOFF_DEBUGGING)
{
if (fp)
ecoff_directive_fmask (0);
else
ecoff_directive_mask (0);
}
else
{
long val;
offsetT offset;
if (!cur_frame_data)
{
if (fp)
as_warn (_(".fmask outside of .ent"));
else
as_warn (_(".mask outside of .ent"));
discard_rest_of_line ();
return;
}
if (get_absolute_expression_and_terminator (&val) != ',')
{
if (fp)
as_warn (_("bad .fmask directive"));
else
as_warn (_("bad .mask directive"));
--input_line_pointer;
discard_rest_of_line ();
return;
}
offset = get_absolute_expression ();
demand_empty_rest_of_line ();
if (fp)
{
cur_frame_data->fmask = val;
cur_frame_data->fmask_offset = offset;
}
else
{
cur_frame_data->mask = val;
cur_frame_data->mask_offset = offset;
}
}
}
static void
s_alpha_frame (dummy)
int dummy ATTRIBUTE_UNUSED;
{
if (ECOFF_DEBUGGING)
ecoff_directive_frame (0);
else
{
long val;
if (!cur_frame_data)
{
as_warn (_(".frame outside of .ent"));
discard_rest_of_line ();
return;
}
cur_frame_data->fp_regno = tc_get_register (1);
SKIP_WHITESPACE ();
if (*input_line_pointer++ != ','
|| get_absolute_expression_and_terminator (&val) != ',')
{
as_warn (_("bad .frame directive"));
--input_line_pointer;
discard_rest_of_line ();
return;
}
cur_frame_data->frame_size = val;
cur_frame_data->ra_regno = tc_get_register (0);
s_ignore (42);
}
}
static void
s_alpha_prologue (ignore)
int ignore ATTRIBUTE_UNUSED;
{
symbolS *sym;
int arg;
arg = get_absolute_expression ();
demand_empty_rest_of_line ();
if (ECOFF_DEBUGGING)
sym = ecoff_get_cur_proc_sym ();
else
sym = cur_frame_data ? cur_frame_data->func_sym : NULL;
if (sym == NULL)
{
as_bad (_(".prologue directive without a preceding .ent directive"));
return;
}
switch (arg)
{
case 0:
S_SET_OTHER (sym, STO_ALPHA_NOPV
| (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD));
break;
case 1:
S_SET_OTHER (sym, STO_ALPHA_STD_GPLOAD
| (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD));
break;
case 2:
break;
default:
as_bad (_("Invalid argument %d to .prologue."), arg);
break;
}
if (cur_frame_data)
cur_frame_data->prologue_sym = symbol_temp_new_now ();
}
static char *first_file_directive;
static void
s_alpha_file (ignore)
int ignore ATTRIBUTE_UNUSED;
{
if (alpha_flag_mdebug < 0 && ! first_file_directive)
{
char *start = input_line_pointer;
size_t len;
discard_rest_of_line ();
len = input_line_pointer - start;
first_file_directive = xmalloc (len + 1);
memcpy (first_file_directive, start, len);
first_file_directive[len] = '\0';
input_line_pointer = start;
}
if (ECOFF_DEBUGGING)
ecoff_directive_file (0);
else
dwarf2_directive_file (0);
}
static void
s_alpha_loc (ignore)
int ignore ATTRIBUTE_UNUSED;
{
if (ECOFF_DEBUGGING)
ecoff_directive_loc (0);
else
dwarf2_directive_loc (0);
}
static void
s_alpha_stab (n)
int n;
{
if (alpha_flag_mdebug < 0)
{
segT sec = subseg_new (".mdebug", 0);
bfd_set_section_flags (stdoutput, sec, SEC_HAS_CONTENTS | SEC_READONLY);
bfd_set_section_alignment (stdoutput, sec, 3);
ecoff_read_begin_hook ();
if (first_file_directive)
{
char *save_ilp = input_line_pointer;
input_line_pointer = first_file_directive;
ecoff_directive_file (0);
input_line_pointer = save_ilp;
free (first_file_directive);
}
alpha_flag_mdebug = 1;
}
s_stab (n);
}
static void
s_alpha_coff_wrapper (which)
int which;
{
static void (* const fns[]) PARAMS ((int)) = {
ecoff_directive_begin,
ecoff_directive_bend,
ecoff_directive_def,
ecoff_directive_dim,
ecoff_directive_endef,
ecoff_directive_scl,
ecoff_directive_tag,
ecoff_directive_val,
};
assert (which >= 0 && which < (int) (sizeof (fns)/sizeof (*fns)));
if (ECOFF_DEBUGGING)
(*fns[which]) (0);
else
{
as_bad (_("ECOFF debugging is disabled."));
ignore_rest_of_line ();
}
}
void
alpha_elf_md_end (void)
{
struct alpha_elf_frame_data *p;
if (cur_frame_data)
as_warn (_(".ent directive without matching .end"));
if (bfd_get_section_by_name (stdoutput, ".eh_frame") != NULL)
return;
for (p = all_frame_data; p ; p = p->next)
if (p->prologue_sym)
{
cfi_new_fde (symbol_temp_new (S_GET_SEGMENT (p->func_sym),
S_GET_VALUE (p->func_sym),
symbol_get_frag (p->func_sym)));
cfi_set_return_column (p->ra_regno);
cfi_add_CFA_def_cfa_register (30);
if (p->fp_regno != 30 || p->mask || p->fmask || p->frame_size)
{
unsigned int mask;
offsetT offset;
cfi_add_advance_loc (p->prologue_sym);
if (p->fp_regno != 30)
if (p->frame_size != 0)
cfi_add_CFA_def_cfa (p->fp_regno, p->frame_size);
else
cfi_add_CFA_def_cfa_register (p->fp_regno);
else if (p->frame_size != 0)
cfi_add_CFA_def_cfa_offset (p->frame_size);
mask = p->mask;
offset = p->mask_offset;
if ((mask >> 26) & 1)
{
cfi_add_CFA_offset (26, offset);
offset += 8;
mask &= ~(1 << 26);
}
while (mask)
{
unsigned int i;
i = mask & -mask;
mask ^= i;
i = ffs (i) - 1;
cfi_add_CFA_offset (i, offset);
offset += 8;
}
mask = p->fmask;
offset = p->fmask_offset;
while (mask)
{
unsigned int i;
i = mask & -mask;
mask ^= i;
i = ffs (i) - 1;
cfi_add_CFA_offset (i + 32, offset);
offset += 8;
}
}
cfi_end_fde (p->func_end_sym);
}
}
static void
s_alpha_usepv (int unused ATTRIBUTE_UNUSED)
{
char *name, name_end;
char *which, which_end;
symbolS *sym;
int other;
name = input_line_pointer;
name_end = get_symbol_end ();
if (! is_name_beginner (*name))
{
as_bad (_(".usepv directive has no name"));
*input_line_pointer = name_end;
ignore_rest_of_line ();
return;
}
sym = symbol_find_or_make (name);
*input_line_pointer++ = name_end;
if (name_end != ',')
{
as_bad (_(".usepv directive has no type"));
ignore_rest_of_line ();
return;
}
SKIP_WHITESPACE ();
which = input_line_pointer;
which_end = get_symbol_end ();
if (strcmp (which, "no") == 0)
other = STO_ALPHA_NOPV;
else if (strcmp (which, "std") == 0)
other = STO_ALPHA_STD_GPLOAD;
else
{
as_bad (_("unknown argument for .usepv"));
other = 0;
}
*input_line_pointer = which_end;
demand_empty_rest_of_line ();
S_SET_OTHER (sym, other | (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD));
}
#endif
void
alpha_cfi_frame_initial_instructions ()
{
cfi_add_CFA_def_cfa_register (30);
}
#ifdef OBJ_EVAX
static void
s_alpha_section (secid)
int secid;
{
int temp;
#define EVAX_SECTION_COUNT 5
static char *section_name[EVAX_SECTION_COUNT + 1] =
{ "NULL", ".rdata", ".comm", ".link", ".ctors", ".dtors" };
if ((secid <= 0) || (secid > EVAX_SECTION_COUNT))
{
as_fatal (_("Unknown section directive"));
demand_empty_rest_of_line ();
return;
}
temp = get_absolute_expression ();
subseg_new (section_name[secid], 0);
demand_empty_rest_of_line ();
alpha_insn_label = NULL;
alpha_auto_align_on = 1;
alpha_current_align = 0;
}
static void
s_alpha_ent (ignore)
int ignore ATTRIBUTE_UNUSED;
{
symbolS *symbol;
expressionS symexpr;
alpha_evax_proc.pdsckind = 0;
alpha_evax_proc.framereg = -1;
alpha_evax_proc.framesize = 0;
alpha_evax_proc.rsa_offset = 0;
alpha_evax_proc.ra_save = AXP_REG_RA;
alpha_evax_proc.fp_save = -1;
alpha_evax_proc.imask = 0;
alpha_evax_proc.fmask = 0;
alpha_evax_proc.prologue = 0;
alpha_evax_proc.type = 0;
expression (&symexpr);
if (symexpr.X_op != O_symbol)
{
as_fatal (_(".ent directive has no symbol"));
demand_empty_rest_of_line ();
return;
}
symbol = make_expr_symbol (&symexpr);
symbol_get_bfdsym (symbol)->flags |= BSF_FUNCTION;
alpha_evax_proc.symbol = symbol;
demand_empty_rest_of_line ();
}
static void
s_alpha_frame (ignore)
int ignore ATTRIBUTE_UNUSED;
{
long val;
alpha_evax_proc.framereg = tc_get_register (1);
SKIP_WHITESPACE ();
if (*input_line_pointer++ != ','
|| get_absolute_expression_and_terminator (&val) != ',')
{
as_warn (_("Bad .frame directive 1./2. param"));
--input_line_pointer;
demand_empty_rest_of_line ();
return;
}
alpha_evax_proc.framesize = val;
(void) tc_get_register (1);
SKIP_WHITESPACE ();
if (*input_line_pointer++ != ',')
{
as_warn (_("Bad .frame directive 3./4. param"));
--input_line_pointer;
demand_empty_rest_of_line ();
return;
}
alpha_evax_proc.rsa_offset = get_absolute_expression ();
}
static void
s_alpha_pdesc (ignore)
int ignore ATTRIBUTE_UNUSED;
{
char *name;
char name_end;
long val;
register char *p;
expressionS exp;
symbolS *entry_sym;
fixS *fixp;
segment_info_type *seginfo = seg_info (alpha_link_section);
if (now_seg != alpha_link_section)
{
as_bad (_(".pdesc directive not in link (.link) section"));
demand_empty_rest_of_line ();
return;
}
if ((alpha_evax_proc.symbol == 0)
|| (!S_IS_DEFINED (alpha_evax_proc.symbol)))
{
as_fatal (_(".pdesc has no matching .ent"));
demand_empty_rest_of_line ();
return;
}
*symbol_get_obj (alpha_evax_proc.symbol) =
(valueT) seginfo->literal_pool_size;
expression (&exp);
if (exp.X_op != O_symbol)
{
as_warn (_(".pdesc directive has no entry symbol"));
demand_empty_rest_of_line ();
return;
}
entry_sym = make_expr_symbol (&exp);
symbol_get_bfdsym (alpha_evax_proc.symbol)->udata.p
= symbol_get_bfdsym (entry_sym);
SKIP_WHITESPACE ();
if (*input_line_pointer++ != ',')
{
as_warn (_("No comma after .pdesc <entryname>"));
demand_empty_rest_of_line ();
return;
}
SKIP_WHITESPACE ();
name = input_line_pointer;
name_end = get_symbol_end ();
if (strncmp (name, "stack", 5) == 0)
{
alpha_evax_proc.pdsckind = PDSC_S_K_KIND_FP_STACK;
}
else if (strncmp (name, "reg", 3) == 0)
{
alpha_evax_proc.pdsckind = PDSC_S_K_KIND_FP_REGISTER;
}
else if (strncmp (name, "null", 4) == 0)
{
alpha_evax_proc.pdsckind = PDSC_S_K_KIND_NULL;
}
else
{
as_fatal (_("unknown procedure kind"));
demand_empty_rest_of_line ();
return;
}
*input_line_pointer = name_end;
demand_empty_rest_of_line ();
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
frag_align (3, 0, 0);
p = frag_more (16);
fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0);
fixp->fx_done = 1;
seginfo->literal_pool_size += 16;
*p = alpha_evax_proc.pdsckind
| ((alpha_evax_proc.framereg == 29) ? PDSC_S_M_BASE_REG_IS_FP : 0);
*(p + 1) = PDSC_S_M_NATIVE | PDSC_S_M_NO_JACKET;
switch (alpha_evax_proc.pdsckind)
{
case PDSC_S_K_KIND_NULL:
*(p + 2) = 0;
*(p + 3) = 0;
break;
case PDSC_S_K_KIND_FP_REGISTER:
*(p + 2) = alpha_evax_proc.fp_save;
*(p + 3) = alpha_evax_proc.ra_save;
break;
case PDSC_S_K_KIND_FP_STACK:
md_number_to_chars (p + 2, (valueT) alpha_evax_proc.rsa_offset, 2);
break;
default:
break;
}
*(p + 4) = 0;
*(p + 5) = alpha_evax_proc.type & 0x0f;
md_number_to_chars (p + 6, (valueT) 0, 2);
fix_new_exp (frag_now, p - frag_now->fr_literal+8, 8, &exp, 0, BFD_RELOC_64);
if (alpha_evax_proc.pdsckind == PDSC_S_K_KIND_NULL)
return;
p = frag_more (8);
fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0);
fixp->fx_done = 1;
seginfo->literal_pool_size += 8;
md_number_to_chars (p, (valueT) alpha_evax_proc.framesize, 4);
md_number_to_chars (p + 4, (valueT) 0, 2);
md_number_to_chars (p + 6, alpha_evax_proc.prologue, 2);
if (alpha_evax_proc.pdsckind == PDSC_S_K_KIND_FP_REGISTER)
return;
p = frag_more (8);
fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0);
fixp->fx_done = 1;
seginfo->literal_pool_size += 8;
md_number_to_chars (p, alpha_evax_proc.imask, 4);
md_number_to_chars (p + 4, alpha_evax_proc.fmask, 4);
}
static void
s_alpha_name (ignore)
int ignore ATTRIBUTE_UNUSED;
{
register char *p;
expressionS exp;
segment_info_type *seginfo = seg_info (alpha_link_section);
if (now_seg != alpha_link_section)
{
as_bad (_(".name directive not in link (.link) section"));
demand_empty_rest_of_line ();
return;
}
expression (&exp);
if (exp.X_op != O_symbol)
{
as_warn (_(".name directive has no symbol"));
demand_empty_rest_of_line ();
return;
}
demand_empty_rest_of_line ();
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
frag_align (3, 0, 0);
p = frag_more (8);
seginfo->literal_pool_size += 8;
fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &exp, 0, BFD_RELOC_64);
}
static void
s_alpha_linkage (ignore)
int ignore ATTRIBUTE_UNUSED;
{
expressionS exp;
char *p;
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
expression (&exp);
if (exp.X_op != O_symbol)
{
as_fatal (_("No symbol after .linkage"));
}
else
{
p = frag_more (LKP_S_K_SIZE);
memset (p, 0, LKP_S_K_SIZE);
fix_new_exp (frag_now, p - frag_now->fr_literal, LKP_S_K_SIZE, &exp, 0,\
BFD_RELOC_ALPHA_LINKAGE);
}
demand_empty_rest_of_line ();
}
static void
s_alpha_code_address (ignore)
int ignore ATTRIBUTE_UNUSED;
{
expressionS exp;
char *p;
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
expression (&exp);
if (exp.X_op != O_symbol)
{
as_fatal (_("No symbol after .code_address"));
}
else
{
p = frag_more (8);
memset (p, 0, 8);
fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &exp, 0,\
BFD_RELOC_ALPHA_CODEADDR);
}
demand_empty_rest_of_line ();
}
static void
s_alpha_fp_save (ignore)
int ignore ATTRIBUTE_UNUSED;
{
alpha_evax_proc.fp_save = tc_get_register (1);
demand_empty_rest_of_line ();
}
static void
s_alpha_mask (ignore)
int ignore ATTRIBUTE_UNUSED;
{
long val;
if (get_absolute_expression_and_terminator (&val) != ',')
{
as_warn (_("Bad .mask directive"));
--input_line_pointer;
}
else
{
alpha_evax_proc.imask = val;
(void) get_absolute_expression ();
}
demand_empty_rest_of_line ();
}
static void
s_alpha_fmask (ignore)
int ignore ATTRIBUTE_UNUSED;
{
long val;
if (get_absolute_expression_and_terminator (&val) != ',')
{
as_warn (_("Bad .fmask directive"));
--input_line_pointer;
}
else
{
alpha_evax_proc.fmask = val;
(void) get_absolute_expression ();
}
demand_empty_rest_of_line ();
}
static void
s_alpha_end (ignore)
int ignore ATTRIBUTE_UNUSED;
{
char c;
c = get_symbol_end ();
*input_line_pointer = c;
demand_empty_rest_of_line ();
alpha_evax_proc.symbol = 0;
}
static void
s_alpha_file (ignore)
int ignore ATTRIBUTE_UNUSED;
{
symbolS *s;
int length;
static char case_hack[32];
sprintf (case_hack, "<CASE:%01d%01d>",
alpha_flag_hash_long_names, alpha_flag_show_after_trunc);
s = symbol_find_or_make (case_hack);
symbol_get_bfdsym (s)->flags |= BSF_FILE;
get_absolute_expression ();
s = symbol_find_or_make (demand_copy_string (&length));
symbol_get_bfdsym (s)->flags |= BSF_FILE;
demand_empty_rest_of_line ();
}
#endif
static void
s_alpha_gprel32 (ignore)
int ignore ATTRIBUTE_UNUSED;
{
expressionS e;
char *p;
SKIP_WHITESPACE ();
expression (&e);
#ifdef OBJ_ELF
switch (e.X_op)
{
case O_constant:
e.X_add_symbol = section_symbol (absolute_section);
e.X_op = O_symbol;
case O_symbol:
break;
default:
abort ();
}
#else
#ifdef OBJ_ECOFF
switch (e.X_op)
{
case O_constant:
e.X_add_symbol = section_symbol (absolute_section);
case O_symbol:
e.X_op = O_subtract;
e.X_op_symbol = alpha_gp_symbol;
break;
default:
abort ();
}
#endif
#endif
if (alpha_auto_align_on && alpha_current_align < 2)
alpha_align (2, (char *) NULL, alpha_insn_label, 0);
if (alpha_current_align > 2)
alpha_current_align = 2;
alpha_insn_label = NULL;
p = frag_more (4);
memset (p, 0, 4);
fix_new_exp (frag_now, p - frag_now->fr_literal, 4,
&e, 0, BFD_RELOC_GPREL32);
}
static void
s_alpha_float_cons (type)
int type;
{
int log_size;
switch (type)
{
default:
case 'f':
case 'F':
log_size = 2;
break;
case 'd':
case 'D':
case 'G':
log_size = 3;
break;
case 'x':
case 'X':
case 'p':
case 'P':
log_size = 4;
break;
}
if (alpha_auto_align_on && alpha_current_align < log_size)
alpha_align (log_size, (char *) NULL, alpha_insn_label, 0);
if (alpha_current_align > log_size)
alpha_current_align = log_size;
alpha_insn_label = NULL;
float_cons (type);
}
static void
s_alpha_proc (is_static)
int is_static ATTRIBUTE_UNUSED;
{
char *name;
char c;
char *p;
symbolS *symbolP;
int temp;
SKIP_WHITESPACE ();
name = input_line_pointer;
c = get_symbol_end ();
p = input_line_pointer;
symbolP = symbol_find_or_make (name);
*p = c;
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
{
*p = 0;
as_warn (_("Expected comma after name \"%s\""), name);
*p = c;
temp = 0;
ignore_rest_of_line ();
}
else
{
input_line_pointer++;
temp = get_absolute_expression ();
}
as_warn (_("unhandled: .proc %s,%d"), name, temp);
demand_empty_rest_of_line ();
}
static void
s_alpha_set (x)
int x ATTRIBUTE_UNUSED;
{
char *name, ch, *s;
int yesno = 1;
SKIP_WHITESPACE ();
name = input_line_pointer;
ch = get_symbol_end ();
s = name;
if (s[0] == 'n' && s[1] == 'o')
{
yesno = 0;
s += 2;
}
if (!strcmp ("reorder", s))
;
else if (!strcmp ("at", s))
alpha_noat_on = !yesno;
else if (!strcmp ("macro", s))
alpha_macros_on = yesno;
else if (!strcmp ("move", s))
;
else if (!strcmp ("volatile", s))
;
else
as_warn (_("Tried to .set unrecognized mode `%s'"), name);
*input_line_pointer = ch;
demand_empty_rest_of_line ();
}
static void
s_alpha_base (ignore)
int ignore ATTRIBUTE_UNUSED;
{
SKIP_WHITESPACE ();
if (*input_line_pointer == '$')
{
input_line_pointer++;
if (*input_line_pointer == 'r')
input_line_pointer++;
}
alpha_gp_register = get_absolute_expression ();
if (alpha_gp_register < 0 || alpha_gp_register > 31)
{
alpha_gp_register = AXP_REG_GP;
as_warn (_("Bad base register, using $%d."), alpha_gp_register);
}
demand_empty_rest_of_line ();
}
static void
s_alpha_align (ignore)
int ignore ATTRIBUTE_UNUSED;
{
int align;
char fill, *pfill;
long max_alignment = 15;
align = get_absolute_expression ();
if (align > max_alignment)
{
align = max_alignment;
as_bad (_("Alignment too large: %d. assumed"), align);
}
else if (align < 0)
{
as_warn (_("Alignment negative: 0 assumed"));
align = 0;
}
if (*input_line_pointer == ',')
{
input_line_pointer++;
fill = get_absolute_expression ();
pfill = &fill;
}
else
pfill = NULL;
if (align != 0)
{
alpha_auto_align_on = 1;
alpha_align (align, pfill, alpha_insn_label, 1);
}
else
{
alpha_auto_align_on = 0;
}
demand_empty_rest_of_line ();
}
static void
s_alpha_stringer (terminate)
int terminate;
{
alpha_current_align = 0;
alpha_insn_label = NULL;
stringer (terminate);
}
static void
s_alpha_space (ignore)
int ignore;
{
alpha_current_align = 0;
alpha_insn_label = NULL;
s_space (ignore);
}
void
alpha_cons_align (size)
int size;
{
int log_size;
log_size = 0;
while ((size >>= 1) != 0)
++log_size;
if (alpha_auto_align_on && alpha_current_align < log_size)
alpha_align (log_size, (char *) NULL, alpha_insn_label, 0);
if (alpha_current_align > log_size)
alpha_current_align = log_size;
alpha_insn_label = NULL;
}
static void
s_alpha_ucons (bytes)
int bytes;
{
int hold = alpha_auto_align_on;
alpha_auto_align_on = 0;
cons (bytes);
alpha_auto_align_on = hold;
}
static void
s_alpha_arch (ignored)
int ignored ATTRIBUTE_UNUSED;
{
char *name, ch;
const struct cpu_type *p;
SKIP_WHITESPACE ();
name = input_line_pointer;
ch = get_symbol_end ();
for (p = cpu_types; p->name; ++p)
if (strcmp (name, p->name) == 0)
{
alpha_target_name = p->name, alpha_target = p->flags;
goto found;
}
as_warn ("Unknown CPU identifier `%s'", name);
found:
*input_line_pointer = ch;
demand_empty_rest_of_line ();
}
#ifdef DEBUG1
static void
alpha_print_token (f, exp)
FILE *f;
const expressionS *exp;
{
switch (exp->X_op)
{
case O_cpregister:
putc (',', f);
case O_pregister:
putc ('(', f);
{
expressionS nexp = *exp;
nexp.X_op = O_register;
print_expr (f, &nexp);
}
putc (')', f);
break;
default:
print_expr (f, exp);
break;
}
}
#endif
const pseudo_typeS md_pseudo_table[] = {
#ifdef OBJ_ECOFF
{"comm", s_alpha_comm, 0},
{"rdata", s_alpha_rdata, 0},
#endif
{"text", s_alpha_text, 0},
{"data", s_alpha_data, 0},
#ifdef OBJ_ECOFF
{"sdata", s_alpha_sdata, 0},
#endif
#ifdef OBJ_ELF
{"section", s_alpha_section, 0},
{"section.s", s_alpha_section, 0},
{"sect", s_alpha_section, 0},
{"sect.s", s_alpha_section, 0},
#endif
#ifdef OBJ_EVAX
{ "pdesc", s_alpha_pdesc, 0},
{ "name", s_alpha_name, 0},
{ "linkage", s_alpha_linkage, 0},
{ "code_address", s_alpha_code_address, 0},
{ "ent", s_alpha_ent, 0},
{ "frame", s_alpha_frame, 0},
{ "fp_save", s_alpha_fp_save, 0},
{ "mask", s_alpha_mask, 0},
{ "fmask", s_alpha_fmask, 0},
{ "end", s_alpha_end, 0},
{ "file", s_alpha_file, 0},
{ "rdata", s_alpha_section, 1},
{ "comm", s_alpha_comm, 0},
{ "link", s_alpha_section, 3},
{ "ctors", s_alpha_section, 4},
{ "dtors", s_alpha_section, 5},
#endif
#ifdef OBJ_ELF
{"ent", s_alpha_ent, 0},
{"end", s_alpha_end, 0},
{"mask", s_alpha_mask, 0},
{"fmask", s_alpha_mask, 1},
{"frame", s_alpha_frame, 0},
{"prologue", s_alpha_prologue, 0},
{"file", s_alpha_file, 5},
{"loc", s_alpha_loc, 9},
{"stabs", s_alpha_stab, 's'},
{"stabn", s_alpha_stab, 'n'},
{"usepv", s_alpha_usepv, 0},
{"begin", s_alpha_coff_wrapper, 0},
{"bend", s_alpha_coff_wrapper, 1},
{"def", s_alpha_coff_wrapper, 2},
{"dim", s_alpha_coff_wrapper, 3},
{"endef", s_alpha_coff_wrapper, 4},
{"scl", s_alpha_coff_wrapper, 5},
{"tag", s_alpha_coff_wrapper, 6},
{"val", s_alpha_coff_wrapper, 7},
#else
{"prologue", s_ignore, 0},
#endif
{"gprel32", s_alpha_gprel32, 0},
{"t_floating", s_alpha_float_cons, 'd'},
{"s_floating", s_alpha_float_cons, 'f'},
{"f_floating", s_alpha_float_cons, 'F'},
{"g_floating", s_alpha_float_cons, 'G'},
{"d_floating", s_alpha_float_cons, 'D'},
{"proc", s_alpha_proc, 0},
{"aproc", s_alpha_proc, 1},
{"set", s_alpha_set, 0},
{"reguse", s_ignore, 0},
{"livereg", s_ignore, 0},
{"base", s_alpha_base, 0},
{"option", s_ignore, 0},
{"aent", s_ignore, 0},
{"ugen", s_ignore, 0},
{"eflag", s_ignore, 0},
{"align", s_alpha_align, 0},
{"double", s_alpha_float_cons, 'd'},
{"float", s_alpha_float_cons, 'f'},
{"single", s_alpha_float_cons, 'f'},
{"ascii", s_alpha_stringer, 0},
{"asciz", s_alpha_stringer, 1},
{"string", s_alpha_stringer, 1},
{"space", s_alpha_space, 0},
{"skip", s_alpha_space, 0},
{"zero", s_alpha_space, 0},
{"uword", s_alpha_ucons, 2},
{"ulong", s_alpha_ucons, 4},
{"uquad", s_alpha_ucons, 8},
#ifdef OBJ_ELF
{"2byte", s_alpha_ucons, 2},
{"4byte", s_alpha_ucons, 4},
{"8byte", s_alpha_ucons, 8},
#endif
{"noalias", s_ignore, 0},
{"alias", s_ignore, 0},
{"arch", s_alpha_arch, 0},
{NULL, 0, 0},
};
static void
create_literal_section (name, secp, symp)
const char *name;
segT *secp;
symbolS **symp;
{
segT current_section = now_seg;
int current_subsec = now_subseg;
segT new_sec;
*secp = new_sec = subseg_new (name, 0);
subseg_set (current_section, current_subsec);
bfd_set_section_alignment (stdoutput, new_sec, 4);
bfd_set_section_flags (stdoutput, new_sec,
SEC_RELOC | SEC_ALLOC | SEC_LOAD | SEC_READONLY
| SEC_DATA);
S_CLEAR_EXTERNAL (*symp = section_symbol (new_sec));
}
#ifdef OBJ_ECOFF
static inline void maybe_set_gp PARAMS ((asection *));
static inline void
maybe_set_gp (sec)
asection *sec;
{
bfd_vma vma;
if (!sec)
return;
vma = bfd_get_section_vma (foo, sec);
if (vma && vma < alpha_gp_value)
alpha_gp_value = vma;
}
static void
select_gp_value ()
{
assert (alpha_gp_value == 0);
alpha_gp_value = 0;
alpha_gp_value--;
maybe_set_gp (alpha_lita_section);
#define GP_ADJUSTMENT (0x8000 - 0x10)
alpha_gp_value += GP_ADJUSTMENT;
S_SET_VALUE (alpha_gp_symbol, alpha_gp_value);
#ifdef DEBUG1
printf (_("Chose GP value of %lx\n"), alpha_gp_value);
#endif
}
#endif
#ifdef OBJ_ELF
int
alpha_elf_section_letter (letter, ptr_msg)
int letter;
char **ptr_msg;
{
if (letter == 's')
return SHF_ALPHA_GPREL;
*ptr_msg = _("Bad .section directive: want a,s,w,x,M,S,G,T in string");
return -1;
}
flagword
alpha_elf_section_flags (flags, attr, type)
flagword flags;
int attr, type ATTRIBUTE_UNUSED;
{
if (attr & SHF_ALPHA_GPREL)
flags |= SEC_SMALL_DATA;
return flags;
}
#endif
static void
alpha_align (n, pfill, label, force)
int n;
char *pfill;
symbolS *label;
int force ATTRIBUTE_UNUSED;
{
if (alpha_current_align >= n)
return;
if (pfill == NULL)
{
if (subseg_text_p (now_seg))
frag_align_code (n, 0);
else
frag_align (n, 0, 0);
}
else
frag_align (n, *pfill, 0);
alpha_current_align = n;
if (label != NULL && S_GET_SEGMENT (label) == now_seg)
{
symbol_set_frag (label, frag_now);
S_SET_VALUE (label, (valueT) frag_now_fix ());
}
record_alignment (now_seg, n);
}
void
alpha_handle_align (fragp)
fragS *fragp;
{
static char const unop[4] = { 0x00, 0x00, 0xfe, 0x2f };
static char const nopunop[8] = {
0x1f, 0x04, 0xff, 0x47,
0x00, 0x00, 0xfe, 0x2f
};
int bytes, fix;
char *p;
if (fragp->fr_type != rs_align_code)
return;
bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
p = fragp->fr_literal + fragp->fr_fix;
fix = 0;
if (bytes & 3)
{
fix = bytes & 3;
memset (p, 0, fix);
p += fix;
bytes -= fix;
}
if (bytes & 4)
{
memcpy (p, unop, 4);
p += 4;
bytes -= 4;
fix += 4;
}
memcpy (p, nopunop, 8);
fragp->fr_fix += fix;
fragp->fr_var = 8;
}
#define md_atof vax_md_atof
#include "config/atof-vax.c"