X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-alpha.c;h=83dbd34444835510eb1850503918e1cc904edd75;hb=f4b97536ed71fbe05b8b0886d63f5ea2c4c66ae8;hp=ba42aaa8bcc610b56976be784541007c3ee5dd2b;hpb=f7e42eb4af140e0068476b586464eaed5569548d;p=binutils-gdb.git diff --git a/gas/config/tc-alpha.c b/gas/config/tc-alpha.c index ba42aaa8bcc..83dbd344448 100644 --- a/gas/config/tc-alpha.c +++ b/gas/config/tc-alpha.c @@ -1,6 +1,6 @@ /* tc-alpha.c - Processor-specific code for the DEC Alpha AXP CPU. - Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 - Free Software Foundation, Inc. + Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003 Free Software Foundation, Inc. Contributed by Carnegie Mellon University, 1993. Written by Alessandro Forin, based on earlier gas-1.38 target CPU files. Modified by Ken Raeburn for gas-2.x and ECOFF support. @@ -60,11 +60,12 @@ #ifdef OBJ_ELF #include "elf/alpha.h" #include "dwarf2dbg.h" +#include "dw2gencfi.h" #endif -#include +#include "safe-ctype.h" -/* Local types */ +/* Local types. */ #define TOKENIZE_ERROR -1 #define TOKENIZE_ERROR_REPORT -2 @@ -72,33 +73,33 @@ #define MAX_INSN_FIXUPS 2 #define MAX_INSN_ARGS 5 -struct alpha_fixup { +struct alpha_fixup +{ expressionS exp; bfd_reloc_code_real_type reloc; }; -struct alpha_insn { +struct alpha_insn +{ unsigned insn; int nfixups; struct alpha_fixup fixups[MAX_INSN_FIXUPS]; - unsigned sequence[MAX_INSN_FIXUPS]; + long sequence; }; -enum alpha_macro_arg { - MACRO_EOA = 1, - MACRO_IR, - MACRO_PIR, - MACRO_OPIR, - MACRO_CPIR, - MACRO_FPR, - MACRO_EXP, - MACRO_LITERAL, - MACRO_BASE, - MACRO_BYTOFF, - MACRO_JSR -}; +enum alpha_macro_arg + { + MACRO_EOA = 1, + MACRO_IR, + MACRO_PIR, + MACRO_OPIR, + MACRO_CPIR, + MACRO_FPR, + MACRO_EXP, + }; -struct alpha_macro { +struct alpha_macro +{ const char *name; void (*emit) PARAMS ((const expressionS *, int, const PTR)); const PTR arg; @@ -110,27 +111,46 @@ struct alpha_macro { #define O_pregister O_md1 /* O_register, in parentheses */ #define O_cpregister O_md2 /* + a leading comma */ -#ifdef RELOC_OP_P -/* Note, the alpha_reloc_op table below depends on the ordering - of O_literal .. O_gprelow. */ +/* The alpha_reloc_op table below depends on the ordering of these. */ #define O_literal O_md3 /* !literal relocation */ -#define O_lituse_base O_md4 /* !lituse_base relocation */ -#define O_lituse_bytoff O_md5 /* !lituse_bytoff relocation */ -#define O_lituse_jsr O_md6 /* !lituse_jsr relocation */ -#define O_gpdisp O_md7 /* !gpdisp relocation */ -#define O_gprelhigh O_md8 /* !gprelhigh relocation */ -#define O_gprellow O_md9 /* !gprellow relocation */ - -#define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_gprellow) -#endif - -/* Macros for extracting the type and number of encoded register tokens */ +#define O_lituse_addr O_md4 /* !lituse_addr relocation */ +#define O_lituse_base O_md5 /* !lituse_base relocation */ +#define O_lituse_bytoff O_md6 /* !lituse_bytoff relocation */ +#define O_lituse_jsr O_md7 /* !lituse_jsr relocation */ +#define O_lituse_tlsgd O_md8 /* !lituse_tlsgd relocation */ +#define O_lituse_tlsldm O_md9 /* !lituse_tlsldm relocation */ +#define O_gpdisp O_md10 /* !gpdisp relocation */ +#define O_gprelhigh O_md11 /* !gprelhigh relocation */ +#define O_gprellow O_md12 /* !gprellow relocation */ +#define O_gprel O_md13 /* !gprel relocation */ +#define O_samegp O_md14 /* !samegp relocation */ +#define O_tlsgd O_md15 /* !tlsgd relocation */ +#define O_tlsldm O_md16 /* !tlsldm relocation */ +#define O_gotdtprel O_md17 /* !gotdtprel relocation */ +#define O_dtprelhi O_md18 /* !dtprelhi relocation */ +#define O_dtprello O_md19 /* !dtprello relocation */ +#define O_dtprel O_md20 /* !dtprel relocation */ +#define O_gottprel O_md21 /* !gottprel relocation */ +#define O_tprelhi O_md22 /* !tprelhi relocation */ +#define O_tprello O_md23 /* !tprello relocation */ +#define O_tprel O_md24 /* !tprel relocation */ + +#define DUMMY_RELOC_LITUSE_ADDR (BFD_RELOC_UNUSED + 1) +#define DUMMY_RELOC_LITUSE_BASE (BFD_RELOC_UNUSED + 2) +#define DUMMY_RELOC_LITUSE_BYTOFF (BFD_RELOC_UNUSED + 3) +#define DUMMY_RELOC_LITUSE_JSR (BFD_RELOC_UNUSED + 4) +#define DUMMY_RELOC_LITUSE_TLSGD (BFD_RELOC_UNUSED + 5) +#define DUMMY_RELOC_LITUSE_TLSLDM (BFD_RELOC_UNUSED + 6) + +#define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_tprel) + +/* Macros for extracting the type and number of encoded register tokens. */ #define is_ir_num(x) (((x) & 32) == 0) #define is_fpr_num(x) (((x) & 32) != 0) #define regno(x) ((x) & 31) -/* Something odd inherited from the old assembler */ +/* Something odd inherited from the old assembler. */ #define note_gpreg(R) (alpha_gprmask |= (1 << (R))) #define note_fpreg(R) (alpha_fprmask |= (1 << (R))) @@ -164,7 +184,7 @@ struct alpha_macro { ^ 0x80000000) - 0x80000000) #endif -/* Macros to build tokens */ +/* Macros to build tokens. */ #define set_tok_reg(t, r) (memset (&(t), 0, sizeof (t)), \ (t).X_op = O_register, \ @@ -186,7 +206,10 @@ struct alpha_macro { (t).X_op = O_constant, \ (t).X_add_number = (n)) -/* Prototypes for all local functions */ +/* Prototypes for all local functions. */ + +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 @@ -197,16 +220,15 @@ 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 *)); + 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 int load_expression - PARAMS ((int, const expressionS *, int *, expressionS *, - const expressionS *)); +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)); @@ -245,6 +267,7 @@ 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)); @@ -257,16 +280,14 @@ 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)); - -#ifdef RELOC_OP_P -static void alpha_adjust_symtab_relocs PARAMS ((bfd *, asection *, PTR)); -#endif /* Generic assembler global variables which must be defined by all targets. */ @@ -300,19 +321,20 @@ const char *md_shortopts = "Fm:g+1h:HG:"; const char *md_shortopts = "Fm:gG:"; #endif -struct option md_longopts[] = { +struct option md_longopts[] = + { #define OPTION_32ADDR (OPTION_MD_BASE) - { "32addr", no_argument, NULL, OPTION_32ADDR }, + { "32addr", no_argument, NULL, OPTION_32ADDR }, #define OPTION_RELAX (OPTION_32ADDR + 1) - { "relax", no_argument, NULL, OPTION_RELAX }, + { "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 }, + { "mdebug", no_argument, NULL, OPTION_MDEBUG }, + { "no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG }, #endif - { NULL, no_argument, NULL, 0 } -}; + { NULL, no_argument, NULL, 0 } + }; size_t md_longopts_size = sizeof (md_longopts); @@ -336,34 +358,33 @@ size_t md_longopts_size = sizeof (md_longopts); #define AXP_REG_GP AXP_REG_PV #endif /* OBJ_EVAX */ -/* The cpu for which we are generating code */ +/* The cpu for which we are generating code. */ static unsigned alpha_target = AXP_OPCODE_BASE; static const char *alpha_target_name = ""; -/* The hash table of instruction opcodes */ +/* The hash table of instruction opcodes. */ static struct hash_control *alpha_opcode_hash; -/* The hash table of macro opcodes */ +/* The hash table of macro opcodes. */ static struct hash_control *alpha_macro_hash; #ifdef OBJ_ECOFF -/* The $gp relocation symbol */ +/* The $gp relocation symbol. */ static symbolS *alpha_gp_symbol; /* XXX: what is this, and why is it exported? */ valueT alpha_gp_value; #endif -/* The current $gp register */ +/* The current $gp register. */ static int alpha_gp_register = AXP_REG_GP; -/* A table of the register symbols */ +/* A table of the register symbols. */ static symbolS *alpha_register_table[64]; -/* Constant sections, or sections of constants */ +/* Constant sections, or sections of constants. */ #ifdef OBJ_ECOFF static segT alpha_lita_section; -static segT alpha_lit4_section; #endif #ifdef OBJ_EVAX static segT alpha_link_section; @@ -375,7 +396,6 @@ static segT alpha_lit8_section; /* Symbols referring to said sections. */ #ifdef OBJ_ECOFF static symbolS *alpha_lita_symbol; -static symbolS *alpha_lit4_symbol; #endif #ifdef OBJ_EVAX static symbolS *alpha_link_symbol; @@ -384,27 +404,21 @@ static symbolS *alpha_dtors_symbol; #endif static symbolS *alpha_lit8_symbol; -/* Literal for .litX+0x8000 within .lita */ +/* Literal for .litX+0x8000 within .lita. */ #ifdef OBJ_ECOFF -static offsetT alpha_lit4_literal; static offsetT alpha_lit8_literal; #endif -#ifdef OBJ_ELF -/* The active .ent symbol. */ -static symbolS *alpha_cur_ent_sym; -#endif - -/* Is the assembler not allowed to use $at? */ +/* Is the assembler not allowed to use $at? */ static int alpha_noat_on = 0; -/* Are macros enabled? */ +/* Are macros enabled? */ static int alpha_macros_on = 1; -/* Are floats disabled? */ +/* Are floats disabled? */ static int alpha_nofloats_on = 0; -/* Are addresses 32 bit? */ +/* Are addresses 32 bit? */ static int alpha_addr32_on = 0; /* Symbol labelling the current insn. When the Alpha gas sees @@ -458,8 +472,7 @@ static int alpha_flag_hash_long_names = 0; /* -+ */ static int alpha_flag_show_after_trunc = 0; /* -H */ /* If the -+ switch is given, then a hash is appended to any name that is - * longer than 64 characters, else longer symbol names are truncated. - */ + longer than 64 characters, else longer symbol names are truncated. */ #endif @@ -469,110 +482,89 @@ static int alpha_flag_show_after_trunc = 0; /* -H */ that op-O_literal indexes into it. */ #define ALPHA_RELOC_TABLE(op) \ -&alpha_reloc_op[ ((!USER_RELOC_P (op)) \ +(&alpha_reloc_op[ ((!USER_RELOC_P (op)) \ ? (abort (), 0) \ - : (int) (op) - (int) O_literal) ] + : (int) (op) - (int) O_literal) ]) -#define LITUSE_BASE 1 -#define LITUSE_BYTOFF 2 -#define LITUSE_JSR 3 +#define DEF(NAME, RELOC, REQ, ALLOW) \ + { #NAME, sizeof(#NAME)-1, O_##NAME, RELOC, REQ, ALLOW} -static const struct alpha_reloc_op_tag { +static const struct alpha_reloc_op_tag +{ const char *name; /* string to lookup */ size_t length; /* size of the string */ - bfd_reloc_code_real_type reloc; /* relocation before frob */ operatorT op; /* which operator to use */ - int lituse; /* addened to specify lituse */ -} alpha_reloc_op[] = { - - { - "literal", /* name */ - sizeof ("literal")-1, /* length */ - BFD_RELOC_ALPHA_USER_LITERAL, /* reloc */ - O_literal, /* op */ - 0, /* lituse */ - }, - - { - "lituse_base", /* name */ - sizeof ("lituse_base")-1, /* length */ - BFD_RELOC_ALPHA_USER_LITUSE_BASE, /* reloc */ - O_lituse_base, /* op */ - LITUSE_BASE, /* lituse */ - }, - - { - "lituse_bytoff", /* name */ - sizeof ("lituse_bytoff")-1, /* length */ - BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF, /* reloc */ - O_lituse_bytoff, /* op */ - LITUSE_BYTOFF, /* lituse */ - }, - - { - "lituse_jsr", /* name */ - sizeof ("lituse_jsr")-1, /* length */ - BFD_RELOC_ALPHA_USER_LITUSE_JSR, /* reloc */ - O_lituse_jsr, /* op */ - LITUSE_JSR, /* lituse */ - }, - - { - "gpdisp", /* name */ - sizeof ("gpdisp")-1, /* length */ - BFD_RELOC_ALPHA_USER_GPDISP, /* reloc */ - O_gpdisp, /* op */ - 0, /* lituse */ - }, - - { - "gprelhigh", /* name */ - sizeof ("gprelhigh")-1, /* length */ - BFD_RELOC_ALPHA_USER_GPRELHIGH, /* reloc */ - O_gprelhigh, /* op */ - 0, /* lituse */ - }, - - { - "gprellow", /* name */ - sizeof ("gprellow")-1, /* length */ - BFD_RELOC_ALPHA_USER_GPRELLOW, /* reloc */ - O_gprellow, /* op */ - 0, /* lituse */ - }, + bfd_reloc_code_real_type reloc; /* relocation before frob */ + unsigned int require_seq : 1; /* require a sequence number */ + unsigned int allow_seq : 1; /* allow a sequence number */ +} +alpha_reloc_op[] = +{ + DEF(literal, BFD_RELOC_ALPHA_ELF_LITERAL, 0, 1), + DEF(lituse_addr, DUMMY_RELOC_LITUSE_ADDR, 1, 1), + DEF(lituse_base, DUMMY_RELOC_LITUSE_BASE, 1, 1), + DEF(lituse_bytoff, DUMMY_RELOC_LITUSE_BYTOFF, 1, 1), + DEF(lituse_jsr, DUMMY_RELOC_LITUSE_JSR, 1, 1), + DEF(lituse_tlsgd, DUMMY_RELOC_LITUSE_TLSGD, 1, 1), + DEF(lituse_tlsldm, DUMMY_RELOC_LITUSE_TLSLDM, 1, 1), + DEF(gpdisp, BFD_RELOC_ALPHA_GPDISP, 1, 1), + DEF(gprelhigh, BFD_RELOC_ALPHA_GPREL_HI16, 0, 0), + DEF(gprellow, BFD_RELOC_ALPHA_GPREL_LO16, 0, 0), + DEF(gprel, BFD_RELOC_GPREL16, 0, 0), + DEF(samegp, BFD_RELOC_ALPHA_BRSGP, 0, 0), + DEF(tlsgd, BFD_RELOC_ALPHA_TLSGD, 0, 1), + DEF(tlsldm, BFD_RELOC_ALPHA_TLSLDM, 0, 1), + DEF(gotdtprel, BFD_RELOC_ALPHA_GOTDTPREL16, 0, 0), + DEF(dtprelhi, BFD_RELOC_ALPHA_DTPREL_HI16, 0, 0), + DEF(dtprello, BFD_RELOC_ALPHA_DTPREL_LO16, 0, 0), + DEF(dtprel, BFD_RELOC_ALPHA_DTPREL16, 0, 0), + DEF(gottprel, BFD_RELOC_ALPHA_GOTTPREL16, 0, 0), + DEF(tprelhi, BFD_RELOC_ALPHA_TPREL_HI16, 0, 0), + DEF(tprello, BFD_RELOC_ALPHA_TPREL_LO16, 0, 0), + DEF(tprel, BFD_RELOC_ALPHA_TPREL16, 0, 0), }; +#undef DEF + static const int alpha_num_reloc_op = sizeof (alpha_reloc_op) / sizeof (*alpha_reloc_op); +#endif /* RELOC_OP_P */ /* Maximum # digits needed to hold the largest sequence # */ #define ALPHA_RELOC_DIGITS 25 -/* Whether a sequence number is valid. */ -#define ALPHA_RELOC_SEQUENCE_OK(X) ((X) > 0 && ((unsigned) (X)) == (X)) - /* Structure to hold explict sequence information. */ -struct alpha_literal_tag +struct alpha_reloc_tag { - fixS *lituse; /* head of linked list of !literals */ + fixS *master; /* the literal reloc */ + fixS *slaves; /* head of linked list of lituses */ segT segment; /* segment relocs are in or undefined_section*/ - int multi_section_p; /* True if more than one section was used */ - unsigned sequence; /* sequence # */ - unsigned n_literals; /* # of literals */ - unsigned n_lituses; /* # of lituses */ + long sequence; /* sequence # */ + unsigned n_master; /* # of literals */ + unsigned n_slaves; /* # of lituses */ + unsigned saw_tlsgd : 1; /* true if ... */ + unsigned saw_tlsldm : 1; + unsigned saw_lu_tlsgd : 1; + unsigned saw_lu_tlsldm : 1; + unsigned multi_section_p : 1; /* true if more than one section was used */ char string[1]; /* printable form of sequence to hash with */ }; /* Hash table to link up literals with the appropriate lituse */ static struct hash_control *alpha_literal_hash; -#endif + +/* Sequence numbers for internal use by macros. */ +static long next_sequence_num = -1; /* A table of CPU names and opcode sets. */ -static const struct cpu_type { +static const struct cpu_type +{ const char *name; unsigned flags; -} cpu_types[] = { +} +cpu_types[] = +{ /* Ad hoc convention: cpu number gets palcode, process code doesn't. This supports usage under DU 4.0b that does ".arch ev4", and usage in MILO that does -m21064. Probably something more @@ -588,6 +580,10 @@ static const struct cpu_type { |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 }, @@ -596,6 +592,8 @@ static const struct cpu_type { { "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 } @@ -603,51 +601,52 @@ static const struct cpu_type { /* The macro table */ -static const struct alpha_macro alpha_macros[] = { +static const struct alpha_macro alpha_macros[] = +{ /* Load/Store macros */ { "lda", emit_lda, NULL, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_LITERAL, MACRO_BASE, MACRO_EOA } }, + { 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_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "ldl_l", emit_ir_load, "ldl_l", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "ldq", emit_ir_load, "ldq", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_LITERAL, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "ldq_l", emit_ir_load, "ldq_l", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "ldq_u", emit_ir_load, "ldq_u", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "ldf", emit_loadstore, "ldf", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "ldg", emit_loadstore, "ldg", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "lds", emit_loadstore, "lds", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "ldt", emit_loadstore, "ldt", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "ldb", emit_ldX, (PTR) 0, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "ldbu", emit_ldXu, (PTR) 0, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "ldw", emit_ldX, (PTR) 1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "ldwu", emit_ldXu, (PTR) 1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "uldw", emit_uldX, (PTR) 1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "uldwu", emit_uldXu, (PTR) 1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "uldl", emit_uldX, (PTR) 2, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "uldlu", emit_uldXu, (PTR) 2, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "uldq", emit_uldXu, (PTR) 3, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "ldgp", emit_ldgp, NULL, { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA } }, @@ -672,34 +671,34 @@ static const struct alpha_macro alpha_macros[] = { #endif { "stl", emit_loadstore, "stl", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "stl_c", emit_loadstore, "stl_c", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "stq", emit_loadstore, "stq", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "stq_c", emit_loadstore, "stq_c", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "stq_u", emit_loadstore, "stq_u", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "stf", emit_loadstore, "stf", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "stg", emit_loadstore, "stg", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "sts", emit_loadstore, "sts", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "stt", emit_loadstore, "stt", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "stb", emit_stX, (PTR) 0, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "stw", emit_stX, (PTR) 1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "ustw", emit_ustX, (PTR) 1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "ustl", emit_ustX, (PTR) 2, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, { "ustq", emit_ustX, (PTR) 3, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, + { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_EOA } }, /* Arithmetic macros */ #if 0 @@ -762,15 +761,15 @@ static const struct alpha_macro alpha_macros[] = { MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, { "jsr", emit_jsrjmp, "jsr", - { MACRO_PIR, MACRO_EXP, MACRO_JSR, MACRO_EOA, - MACRO_PIR, MACRO_JSR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_JSR, MACRO_EOA, - MACRO_EXP, MACRO_JSR, MACRO_EOA } }, + { 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_JSR, MACRO_EOA, - MACRO_PIR, MACRO_JSR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_JSR, MACRO_EOA, - MACRO_EXP, MACRO_JSR, MACRO_EOA } }, + { 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, @@ -815,8 +814,7 @@ md_begin () assert (e.X_op == O_max); } - /* Create the opcode hash table */ - + /* Create the opcode hash table. */ alpha_opcode_hash = hash_new (); for (i = 0; i < alpha_num_opcodes;) { @@ -825,7 +823,8 @@ md_begin () 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); + as_fatal (_("internal error: can't hash opcode `%s': %s"), + name, retval); /* Some opcodes include modifiers of various sorts with a "/mod" syntax, like the architecture manual suggests. However, for @@ -849,8 +848,7 @@ md_begin () continue; } - /* Create the macro hash table */ - + /* Create the macro hash table. */ alpha_macro_hash = hash_new (); for (i = 0; i < alpha_num_macros;) { @@ -868,11 +866,11 @@ md_begin () continue; } - /* Construct symbols for each of the registers */ - + /* Construct symbols for each of the registers. */ for (i = 0; i < 32; ++i) { char name[4]; + sprintf (name, "$%d", i); alpha_register_table[i] = symbol_create (name, reg_section, i, &zero_address_frag); @@ -880,12 +878,13 @@ md_begin () for (; i < 64; ++i) { char name[5]; + sprintf (name, "$f%d", i - 32); alpha_register_table[i] = symbol_create (name, reg_section, i, &zero_address_frag); } - /* Create the special symbols and sections we'll be using */ + /* Create the special symbols and sections we'll be using. */ /* So .sbss will get used for tiny objects. */ bfd_set_gp_size (stdoutput, g_switch_value); @@ -912,12 +911,10 @@ md_begin () } #endif /* OBJ_ELF */ - subseg_set (text_section, 0); - -#ifdef RELOC_OP_P /* Create literal lookup hash table. */ alpha_literal_hash = hash_new (); -#endif + + subseg_set (text_section, 0); } /* The public interface to the instruction assembler. */ @@ -926,12 +923,12 @@ void md_assemble (str) char *str; { - char opname[32]; /* current maximum is 13 */ + char opname[32]; /* Current maximum is 13. */ expressionS tok[MAX_INSN_ARGS]; int ntok, trunclen; size_t opnamelen; - /* split off the opcode */ + /* Split off the opcode. */ opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_/46819"); trunclen = (opnamelen < sizeof (opname) - 1 ? opnamelen @@ -939,7 +936,7 @@ md_assemble (str) memcpy (opname, str, trunclen); opname[trunclen] = '\0'; - /* tokenize the rest of the line */ + /* Tokenize the rest of the line. */ if ((ntok = tokenize_arguments (str + opnamelen, tok, MAX_INSN_ARGS)) < 0) { if (ntok != TOKENIZE_ERROR_REPORT) @@ -948,7 +945,7 @@ md_assemble (str) return; } - /* finish it off */ + /* Finish it off. */ assemble_tokens (opname, tok, ntok, alpha_macros_on); } @@ -970,7 +967,7 @@ md_section_align (seg, size) of LITTLENUMS emitted is stored in *SIZEP. An error message is returned, or NULL on OK. */ -/* Equal to MAX_PRECISION in atof-ieee.c */ +/* Equal to MAX_PRECISION in atof-ieee.c. */ #define MAX_LITTLENUMS 6 extern char *vax_md_atof PARAMS ((int, char *, int *)); @@ -1115,9 +1112,9 @@ md_show_usage (stream) Alpha options:\n\ -32addr treat addresses as 32-bit values\n\ -F lack floating point instructions support\n\ --mev4 | -mev45 | -mev5 | -mev56 | -mpca56 | -mev6 | -mall\n\ +-mev4 | -mev45 | -mev5 | -mev56 | -mpca56 | -mev6 | -mev67 | -mev68 | -mall\n\ specify variant of Alpha architecture\n\ --m21064 | -m21066 | -m21164 | -m21164a | -m21164pc | -m21264\n\ +-m21064 | -m21066 | -m21164 | -m21164a | -m21164pc | -m21264 | -m21264a | -m21264b\n\ these variants include PALcode opcodes\n"), stream); #ifdef OBJ_EVAX @@ -1139,12 +1136,12 @@ md_pcrel_from (fixP) valueT addr = fixP->fx_where + fixP->fx_frag->fr_address; switch (fixP->fx_r_type) { - case BFD_RELOC_ALPHA_GPDISP: - case BFD_RELOC_ALPHA_GPDISP_HI16: - case BFD_RELOC_ALPHA_GPDISP_LO16: - return addr; + case BFD_RELOC_23_PCREL_S2: + case BFD_RELOC_ALPHA_HINT: + case BFD_RELOC_ALPHA_BRSGP: + return addr + 4; default: - return fixP->fx_size + addr; + return addr; } } @@ -1158,28 +1155,32 @@ md_pcrel_from (fixP) the distance to the "lda" instruction for setting the addend to GPDISP. */ -int -md_apply_fix (fixP, valueP) +void +md_apply_fix3 (fixP, valP, seg) fixS *fixP; - valueT *valueP; + valueT * valP; + segT seg; { char * const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where; - valueT value = *valueP; + valueT value = * valP; unsigned image, size; switch (fixP->fx_r_type) { /* The GPDISP relocations are processed internally with a symbol - referring to the current function; we need to drop in a value - which, when added to the address of the start of the function, - gives the desired GP. */ + referring to the current function's section; we need to drop + in a value which, when added to the address of the start of + the function, gives the desired GP. */ case BFD_RELOC_ALPHA_GPDISP_HI16: { fixS *next = fixP->fx_next; - assert (next->fx_r_type == BFD_RELOC_ALPHA_GPDISP_LO16); - fixP->fx_offset = (next->fx_frag->fr_address + next->fx_where - - fixP->fx_frag->fr_address - fixP->fx_where); + /* With user-specified !gpdisp relocations, we can be missing + the matching LO16 reloc. We will have already issued an + error message. */ + if (next) + fixP->fx_offset = (next->fx_frag->fr_address + next->fx_where + - fixP->fx_frag->fr_address - fixP->fx_where); value = (value - sign_extend_16 (value)) >> 16; } @@ -1196,7 +1197,7 @@ md_apply_fix (fixP, valueP) #endif do_reloc_gp: - fixP->fx_addsy = section_symbol (now_seg); + fixP->fx_addsy = section_symbol (seg); md_number_to_chars (fixpos, value, 2); break; @@ -1220,7 +1221,7 @@ md_apply_fix (fixP, valueP) md_number_to_chars (fixpos, value, size); goto done; } - return 1; + return; #ifdef OBJ_ECOFF case BFD_RELOC_GPREL32: @@ -1229,11 +1230,13 @@ md_apply_fix (fixP, valueP) /* FIXME: inherited this obliviousness of `value' -- why? */ md_number_to_chars (fixpos, -alpha_gp_value, 4); break; -#endif -#ifdef OBJ_ELF +#else case BFD_RELOC_GPREL32: - return 1; #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) @@ -1242,7 +1245,7 @@ md_apply_fix (fixP, valueP) image = (image & ~0x1FFFFF) | ((value >> 2) & 0x1FFFFF); goto write_done; } - return 1; + return; case BFD_RELOC_ALPHA_HINT: if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0) @@ -1251,43 +1254,41 @@ md_apply_fix (fixP, valueP) image = (image & ~0x3FFF) | ((value >> 2) & 0x3FFF); goto write_done; } - return 1; + 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 1; - - case BFD_RELOC_ALPHA_LITUSE: - return 1; + return; #endif -#ifdef OBJ_ELF case BFD_RELOC_ALPHA_ELF_LITERAL: case BFD_RELOC_ALPHA_LITUSE: - return 1; -#endif -#ifdef OBJ_EVAX case BFD_RELOC_ALPHA_LINKAGE: case BFD_RELOC_ALPHA_CODEADDR: - return 1; -#endif - -#ifdef RELOC_OP_P - case BFD_RELOC_ALPHA_USER_LITERAL: - case BFD_RELOC_ALPHA_USER_LITUSE_BASE: - case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF: - case BFD_RELOC_ALPHA_USER_LITUSE_JSR: - return 1; - - case BFD_RELOC_ALPHA_USER_GPDISP: - case BFD_RELOC_ALPHA_USER_GPRELHIGH: - case BFD_RELOC_ALPHA_USER_GPRELLOW: - abort (); -#endif + return; case BFD_RELOC_VTABLE_INHERIT: case BFD_RELOC_VTABLE_ENTRY: - return 1; + return; default: { @@ -1317,7 +1318,7 @@ md_apply_fix (fixP, valueP) } if (fixP->fx_addsy != 0 || fixP->fx_pcrel != 0) - return 1; + return; else { as_warn_where (fixP->fx_file, fixP->fx_line, @@ -1330,12 +1331,9 @@ write_done: done: fixP->fx_done = 1; - return 0; } -/* - * Look for a register name in the given symbol. - */ +/* Look for a register name in the given symbol. */ symbolS * md_undefined_symbol (name) @@ -1354,7 +1352,7 @@ md_undefined_symbol (name) /* FALLTHRU */ case 'r': - if (!isdigit (*++name)) + if (!ISDIGIT (*++name)) break; /* FALLTHRU */ @@ -1362,7 +1360,7 @@ md_undefined_symbol (name) 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') + else if (name[0] != '0' && ISDIGIT (name[1]) && name[2] == '\0') { num = (name[0] - '0') * 10 + name[1] - '0'; if (num >= 32) @@ -1423,7 +1421,7 @@ alpha_define_label (sym) } /* Return true if we must always emit a reloc for a type and false if - there is some hope of resolving it a assembly time. */ + there is some hope of resolving it at assembly time. */ int alpha_force_relocation (f) @@ -1437,42 +1435,33 @@ alpha_force_relocation (f) case BFD_RELOC_ALPHA_GPDISP_HI16: case BFD_RELOC_ALPHA_GPDISP_LO16: case BFD_RELOC_ALPHA_GPDISP: -#ifdef OBJ_ECOFF case BFD_RELOC_ALPHA_LITERAL: -#endif -#ifdef OBJ_ELF case BFD_RELOC_ALPHA_ELF_LITERAL: -#endif case BFD_RELOC_ALPHA_LITUSE: + case BFD_RELOC_GPREL16: case BFD_RELOC_GPREL32: -#ifdef OBJ_EVAX + case BFD_RELOC_ALPHA_GPREL_HI16: + case BFD_RELOC_ALPHA_GPREL_LO16: case BFD_RELOC_ALPHA_LINKAGE: case BFD_RELOC_ALPHA_CODEADDR: -#endif -#ifdef RELOC_OP_P - case BFD_RELOC_ALPHA_USER_LITERAL: - case BFD_RELOC_ALPHA_USER_LITUSE_BASE: - case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF: - case BFD_RELOC_ALPHA_USER_LITUSE_JSR: - case BFD_RELOC_ALPHA_USER_GPDISP: - case BFD_RELOC_ALPHA_USER_GPRELHIGH: - case BFD_RELOC_ALPHA_USER_GPRELLOW: -#endif - case BFD_RELOC_VTABLE_INHERIT: - case BFD_RELOC_VTABLE_ENTRY: + 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; - case BFD_RELOC_23_PCREL_S2: - case BFD_RELOC_32: - case BFD_RELOC_64: - case BFD_RELOC_ALPHA_HINT: - return 0; - default: - assert ((int) f->fx_r_type < 0 - && -(int) f->fx_r_type < (int) alpha_num_operands); - return 0; + break; } + + return generic_force_reloc (f); } /* Return true if we can partially resolve a relocation now. */ @@ -1481,12 +1470,6 @@ int alpha_fix_adjustable (f) fixS *f; { -#ifdef OBJ_ELF - /* Prevent all adjustments to global symbols */ - if (S_IS_EXTERN (f->fx_addsy) || S_IS_WEAK (f->fx_addsy)) - return 0; -#endif - /* Are there any relocation types for which we must generate a reloc but we can adjust the values contained within it? */ switch (f->fx_r_type) @@ -1496,44 +1479,77 @@ alpha_fix_adjustable (f) case BFD_RELOC_ALPHA_GPDISP: return 0; -#ifdef OBJ_ECOFF case BFD_RELOC_ALPHA_LITERAL: -#endif -#ifdef OBJ_ELF case BFD_RELOC_ALPHA_ELF_LITERAL: -#endif -#ifdef RELOC_OP_P - case BFD_RELOC_ALPHA_USER_LITERAL: -#endif -#ifdef OBJ_EVAX + case BFD_RELOC_ALPHA_LITUSE: case BFD_RELOC_ALPHA_LINKAGE: case BFD_RELOC_ALPHA_CODEADDR: -#endif return 1; - case BFD_RELOC_ALPHA_LITUSE: -#ifdef RELOC_OP_P - case BFD_RELOC_ALPHA_USER_LITUSE_BASE: - case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF: - case BFD_RELOC_ALPHA_USER_LITUSE_JSR: - case BFD_RELOC_ALPHA_USER_GPDISP: - case BFD_RELOC_ALPHA_USER_GPRELHIGH: - case BFD_RELOC_ALPHA_USER_GPRELLOW: -#endif 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: + /* ??? No idea why we can't return a reference to .tbss+10, but + we're preventing this in the other assemblers. Follow for now. */ + return 0; + +#ifdef OBJ_ELF + case BFD_RELOC_ALPHA_BRSGP: + /* If we have a BRSGP reloc to a local symbol, adjust it to BRADDR and + let it get resolved at assembly time. */ + { + symbolS *sym = f->fx_addsy; + const char *name; + int offset = 0; + + if (generic_force_reloc (f)) + return 0; + + switch (S_GET_OTHER (sym) & STO_ALPHA_STD_GPLOAD) + { + case STO_ALPHA_NOPV: + break; + case STO_ALPHA_STD_GPLOAD: + offset = 8; + break; + default: + if (S_IS_LOCAL (sym)) + name = ""; + 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: - assert ((int) f->fx_r_type < 0 - && - (int) f->fx_r_type < (int) alpha_num_operands); return 1; } /*NOTREACHED*/ @@ -1577,7 +1593,7 @@ tc_gen_reloc (sec, fixp) #ifdef OBJ_ECOFF if (fixp->fx_r_type == BFD_RELOC_ALPHA_LITERAL) { - /* fake out bfd_perform_relocation. sigh */ + /* Fake out bfd_perform_relocation. sigh. */ reloc->addend = -alpha_gp_value; } else @@ -1585,13 +1601,13 @@ tc_gen_reloc (sec, fixp) { reloc->addend = fixp->fx_offset; #ifdef OBJ_ELF - /* - * Ohhh, this is ugly. The problem is that if this is a local global - * symbol, the relocation will entirely be performed at link time, not - * at assembly time. bfd_perform_reloc doesn't know about this sort - * of thing, and as a result we need to fake it out here. - */ - if ((S_IS_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)) + /* Ohhh, this is ugly. The problem is that if this is a local global + symbol, the relocation will entirely be performed at link time, not + at assembly time. bfd_perform_reloc doesn't know about this sort + of thing, and as a result we need to fake it out here. */ + 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 @@ -1649,34 +1665,48 @@ alpha_frob_file_before_adjust () #endif /* OBJ_ECOFF */ -#ifdef RELOC_OP_P +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; +} /* Before the relocations are written, reorder them, so that user supplied !lituse relocations follow the appropriate !literal - relocations. Also convert the gas-internal relocations to the - appropriate linker relocations. */ + relocations, and similarly for !gpdisp relocations. */ void -alpha_adjust_symtab () +alpha_before_fix () { if (alpha_literal_hash) - { -#ifdef DEBUG2_ALPHA - fprintf (stderr, "alpha_adjust_symtab called\n"); -#endif - - /* Go over each section, reordering the relocations so that all - of the explicit LITUSE's are adjacent to the explicit - LITERAL's. */ - bfd_map_over_sections (stdoutput, alpha_adjust_symtab_relocs, - (char *) 0); - } + bfd_map_over_sections (stdoutput, alpha_adjust_relocs, NULL); } - -/* Inner function to move LITUSE's next to the LITERAL. */ static void -alpha_adjust_symtab_relocs (abfd, sec, ptr) +alpha_adjust_relocs (abfd, sec, ptr) bfd *abfd ATTRIBUTE_UNUSED; asection *sec; PTR ptr ATTRIBUTE_UNUSED; @@ -1685,14 +1715,7 @@ alpha_adjust_symtab_relocs (abfd, sec, ptr) fixS **prevP; fixS *fixp; fixS *next; - fixS *lituse; - int n_lituses = 0; - -#ifdef DEBUG2_ALPHA - int n = 0; - int n_literals = 0; - int n_dup_literals = 0; -#endif + fixS *slave; /* If seginfo is NULL, we did not create this section; don't do anything with it. By using a pointer to a pointer, we can update @@ -1704,121 +1727,137 @@ alpha_adjust_symtab_relocs (abfd, sec, ptr) if (! seginfo->fix_root) return; - /* First rebuild the fixup chain without the expicit lituse's. */ - prevP = &(seginfo->fix_root); + /* First rebuild the fixup chain without the expicit lituse and + gpdisp_lo16 relocs. */ + prevP = &seginfo->fix_root; for (fixp = seginfo->fix_root; fixp; fixp = next) { next = fixp->fx_next; fixp->fx_next = (fixS *) 0; -#ifdef DEBUG2_ALPHA - n++; -#endif switch (fixp->fx_r_type) { - default: - *prevP = fixp; - prevP = &(fixp->fx_next); -#ifdef DEBUG2_ALPHA - fprintf (stderr, - "alpha_adjust_symtab_relocs: 0x%lx, other relocation %s\n", - (long) fixp, - bfd_get_reloc_code_name (fixp->fx_r_type)); -#endif - break; - - case BFD_RELOC_ALPHA_USER_LITERAL: - *prevP = fixp; - prevP = &(fixp->fx_next); - /* prevent assembler from trying to adjust the offset */ -#ifdef DEBUG2_ALPHA - n_literals++; - if (fixp->tc_fix_data.info->n_literals != 1) - n_dup_literals++; - fprintf (stderr, - "alpha_adjust_symtab_relocs: 0x%lx, !literal!%.6d, # literals = %2d\n", - (long) fixp, - fixp->tc_fix_data.info->sequence, - fixp->tc_fix_data.info->n_literals); + 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; - /* do not link in lituse's */ - case BFD_RELOC_ALPHA_USER_LITUSE_BASE: - case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF: - case BFD_RELOC_ALPHA_USER_LITUSE_JSR: - n_lituses++; - if (fixp->tc_fix_data.info->n_literals == 0) + 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 !literal!%d was found"), + _("No ldah !gpdisp!%ld was found"), fixp->tc_fix_data.info->sequence); -#ifdef DEBUG2_ALPHA - fprintf (stderr, - "alpha_adjust_symtab_relocs: 0x%lx, !lituse !%.6d, # lituses = %2d, next_lituse = 0x%lx\n", - (long) fixp, - fixp->tc_fix_data.info->sequence, - fixp->tc_fix_data.info->n_lituses, - (long) fixp->tc_fix_data.next_lituse); -#endif + break; + + case BFD_RELOC_ALPHA_ELF_LITERAL: + if (fixp->tc_fix_data.info + && (fixp->tc_fix_data.info->saw_tlsgd + || fixp->tc_fix_data.info->saw_tlsldm)) + break; + /* FALLTHRU */ + + default: + *prevP = fixp; + prevP = &fixp->fx_next; break; } } - /* If there were any lituses, go and add them to the chain, unless there is - more than one !literal for a given sequence number. They are linked - through the next_lituse field in reverse order, so as we go through the - next_lituse chain, we effectively reverse the chain once again. If there - was more than one !literal, we fall back to loading up the address w/o - optimization. Also, if the !literals/!lituses are spread in different - segments (happens in the Linux kernel semaphores), suppress the - optimization. */ - if (n_lituses) + /* Go back and re-chain dependent relocations. They are currently + linked through the next_reloc field in reverse order, so as we + go through the next_reloc chain, we effectively reverse the chain + once again. + + Except if there is more than one !literal for a given sequence + number. In that case, the programmer and/or compiler is not sure + how control flows from literal to lituse, and we can't be sure to + get the relaxation correct. + + ??? Well, actually we could, if there are enough lituses such that + we can make each literal have at least one of each lituse type + present. Not implemented. + + Also suppress the optimization if the !literals/!lituses are spread + in different segments. This can happen with "intersting" uses of + inline assembly; examples are present in the Linux kernel semaphores. */ + + for (fixp = seginfo->fix_root; fixp; fixp = next) { - for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next) + next = fixp->fx_next; + switch (fixp->fx_r_type) { - 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) { - default: + 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; + } - case BFD_RELOC_ALPHA_USER_LITERAL: -#ifdef OBJ_ELF - fixp->fx_r_type = BFD_RELOC_ALPHA_ELF_LITERAL; -#else - fixp->fx_r_type = BFD_RELOC_ALPHA_LITERAL; /* XXX check this */ -#endif - if (fixp->tc_fix_data.info->n_literals == 1 - && ! fixp->tc_fix_data.info->multi_section_p) + fixp->tc_fix_data.info->master->fx_next = fixp->fx_next; + fixp->fx_next = fixp->tc_fix_data.info->master; + fixp = fixp->fx_next; + /* FALLTHRU */ + + 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) { - for (lituse = fixp->tc_fix_data.info->lituse; - lituse != (fixS *) 0; - lituse = lituse->tc_fix_data.next_lituse) - { - lituse->fx_next = fixp->fx_next; - fixp->fx_next = lituse; - } + slave->fx_next = fixp->fx_next; + fixp->fx_next = slave; } - break; + } + break; - case BFD_RELOC_ALPHA_USER_LITUSE_BASE: - case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF: - case BFD_RELOC_ALPHA_USER_LITUSE_JSR: - fixp->fx_r_type = BFD_RELOC_ALPHA_LITUSE; - break; + 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 DEBUG2_ALPHA - fprintf (stderr, "alpha_adjust_symtab_relocs: %s, %d literal%s, %d duplicate literal%s, %d lituse%s\n\n", - sec->name, - n_literals, (n_literals == 1) ? "" : "s", - n_dup_literals, (n_dup_literals == 1) ? "" : "s", - n_lituses, (n_lituses == 1) ? "" : "s"); -#endif } - -#endif /* RELOC_OP_P */ #ifdef DEBUG_ALPHA static void @@ -1833,6 +1872,7 @@ debug_exp (tok, ntok) { expressionS *t = &tok[i]; const char *name; + switch (t->X_op) { default: name = "unknown"; break; @@ -1869,19 +1909,27 @@ debug_exp (tok, ntok) 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_md10: name = "O_md10"; break; - case O_md11: name = "O_md11"; break; - case O_md12: name = "O_md12"; break; - case O_md13: name = "O_md13"; break; - case O_md14: name = "O_md14"; break; - case O_md15: name = "O_md15"; break; - case O_md16: name = "O_md16"; break; + 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, @@ -1918,10 +1966,15 @@ tokenize_arguments (str, tok, ntok) memset (tok, 0, sizeof (*tok) * ntok); - /* Save and restore input_line_pointer around this function */ + /* Save and restore input_line_pointer around this function. */ old_input_line_pointer = input_line_pointer; input_line_pointer = str; +#ifdef RELOC_OP_P + /* ??? Wrest control of ! away from the regular expression parser. */ + is_end_of_line[(unsigned char) '!'] = 1; +#endif + while (tok < end_tok && *input_line_pointer) { SKIP_WHITESPACE (); @@ -1936,7 +1989,8 @@ tokenize_arguments (str, tok, ntok) assembly language statement, and has the following form: !relocation_type!sequence_number. */ if (reloc_found_p) - { /* only support one relocation op per insn */ + { + /* Only support one relocation op per insn. */ as_bad (_("More than one relocation op per insn")); goto err_report; } @@ -1944,59 +1998,66 @@ tokenize_arguments (str, tok, ntok) if (!saw_arg) goto err; - for (p = ++input_line_pointer; - ((c = *p) != '!' && c != ';' && c != '#' && c != ',' - && !is_end_of_line[c]); - p++) - ; + ++input_line_pointer; + SKIP_WHITESPACE (); + p = input_line_pointer; + c = get_symbol_end (); - /* Parse !relocation_type */ - len = p - input_line_pointer; + /* Parse !relocation_type. */ + len = input_line_pointer - p; if (len == 0) { as_bad (_("No relocation operand")); goto err_report; } - if (c != '!') - { - as_bad (_("No !sequence-number after !%s"), input_line_pointer); - goto err_report; - } - r = &alpha_reloc_op[0]; for (i = alpha_num_reloc_op - 1; i >= 0; i--, r++) - { - if (len == r->length - && memcmp (input_line_pointer, r->name, len) == 0) - break; - } + if (len == r->length && memcmp (p, r->name, len) == 0) + break; if (i < 0) { - as_bad (_("Unknown relocation operand: !%s"), - input_line_pointer); + as_bad (_("Unknown relocation operand: !%s"), p); goto err_report; } - input_line_pointer = ++p; - - /* Parse !sequence_number */ - memset (tok, '\0', sizeof (expressionS)); - expression (tok); + *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; + } - if (tok->X_op != O_constant - || ! ALPHA_RELOC_SEQUENCE_OK (tok->X_add_number)) + tok->X_add_number = 0; + } + else { - as_bad (_("Bad sequence number: !%s!%s"), - r->name, input_line_pointer); - goto err_report; + if (! r->allow_seq) + { + as_bad (_("!%s does not use a sequence number"), p); + goto err_report; + } + + input_line_pointer++; + + /* Parse !sequence_number. */ + expression (tok); + if (tok->X_op != O_constant || tok->X_add_number <= 0) + { + as_bad (_("Bad sequence number: !%s!%s"), + r->name, input_line_pointer); + goto err_report; + } } tok->X_op = r->op; reloc_found_p = 1; ++tok; break; -#endif +#endif /* RELOC_OP_P */ case ',': ++input_line_pointer; @@ -2021,7 +2082,7 @@ tokenize_arguments (str, tok, ntok) break; } - /* ... then fall through to plain expression */ + /* ... then fall through to plain expression. */ input_line_pointer = hold; } @@ -2048,18 +2109,25 @@ fini: #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; -#endif } /* Search forward through all variants of an opcode looking for a @@ -2081,7 +2149,7 @@ find_opcode_match (first_opcode, tok, pntok, pcpumatch) const unsigned char *opidx; int tokidx = 0; - /* Don't match opcodes that don't exist on this architecture */ + /* Don't match opcodes that don't exist on this architecture. */ if (!(opcode->flags & alpha_target)) goto match_failed; @@ -2091,11 +2159,11 @@ find_opcode_match (first_opcode, tok, pntok, pcpumatch) { const struct alpha_operand *operand = &alpha_operands[*opidx]; - /* only take input from real operands */ + /* Only take input from real operands. */ if (operand->flags & AXP_OPERAND_FAKE) continue; - /* when we expect input, make sure we have it */ + /* When we expect input, make sure we have it. */ if (tokidx >= ntok) { if ((operand->flags & AXP_OPERAND_OPTIONAL_MASK) == 0) @@ -2103,7 +2171,7 @@ find_opcode_match (first_opcode, tok, pntok, pcpumatch) continue; } - /* match operand type with expression type */ + /* Match operand type with expression type. */ switch (operand->flags & AXP_OPERAND_TYPECHECK_MASK) { case AXP_OPERAND_IR: @@ -2145,13 +2213,13 @@ find_opcode_match (first_opcode, tok, pntok, pcpumatch) break; default: - /* everything else should have been fake */ + /* Everything else should have been fake. */ abort (); } ++tokidx; } - /* possible match -- did we use all of our input? */ + /* Possible match -- did we use all of our input? */ if (tokidx == ntok) { *pntok = ntok; @@ -2160,7 +2228,7 @@ find_opcode_match (first_opcode, tok, pntok, pcpumatch) match_failed:; } - while (++opcode - alpha_opcodes < alpha_num_opcodes + while (++opcode - alpha_opcodes < (int) alpha_num_opcodes && !strcmp (opcode->name, first_opcode->name)); if (*pcpumatch) @@ -2197,7 +2265,7 @@ find_macro_match (first_macro, tok, pntok) tokidx = 0; break; - /* index register */ + /* Index register. */ case MACRO_IR: if (tokidx >= ntok || tok[tokidx].X_op != O_register || !is_ir_num (tok[tokidx].X_add_number)) @@ -2205,7 +2273,7 @@ find_macro_match (first_macro, tok, pntok) ++tokidx; break; - /* parenthesized index register */ + /* Parenthesized index register. */ case MACRO_PIR: if (tokidx >= ntok || tok[tokidx].X_op != O_pregister || !is_ir_num (tok[tokidx].X_add_number)) @@ -2213,14 +2281,14 @@ find_macro_match (first_macro, tok, pntok) ++tokidx; break; - /* optional parenthesized index register */ + /* Optional parenthesized index register. */ case MACRO_OPIR: if (tokidx < ntok && tok[tokidx].X_op == O_pregister && is_ir_num (tok[tokidx].X_add_number)) ++tokidx; break; - /* leading comma with a parenthesized index register */ + /* Leading comma with a parenthesized index register. */ case MACRO_CPIR: if (tokidx >= ntok || tok[tokidx].X_op != O_cpregister || !is_ir_num (tok[tokidx].X_add_number)) @@ -2228,7 +2296,7 @@ find_macro_match (first_macro, tok, pntok) ++tokidx; break; - /* floating point register */ + /* Floating point register. */ case MACRO_FPR: if (tokidx >= ntok || tok[tokidx].X_op != O_register || !is_fpr_num (tok[tokidx].X_add_number)) @@ -2236,7 +2304,7 @@ find_macro_match (first_macro, tok, pntok) ++tokidx; break; - /* normal expression */ + /* Normal expression. */ case MACRO_EXP: if (tokidx >= ntok) goto match_failed; @@ -2247,7 +2315,6 @@ find_macro_match (first_macro, tok, pntok) case O_register: case O_pregister: case O_cpregister: -#ifdef RELOC_OP_P case O_literal: case O_lituse_base: case O_lituse_bytoff: @@ -2255,7 +2322,8 @@ find_macro_match (first_macro, tok, pntok) case O_gpdisp: case O_gprelhigh: case O_gprellow: -#endif + case O_gprel: + case O_samegp: goto match_failed; default: @@ -2264,38 +2332,6 @@ find_macro_match (first_macro, tok, pntok) ++tokidx; break; - /* optional !literal! */ - case MACRO_LITERAL: -#ifdef RELOC_OP_P - if (tokidx < ntok && tok[tokidx].X_op == O_literal) - tokidx++; -#endif - break; - - /* optional !lituse_base! */ - case MACRO_BASE: -#ifdef RELOC_OP_P - if (tokidx < ntok && tok[tokidx].X_op == O_lituse_base) - tokidx++; -#endif - break; - - /* optional !lituse_bytoff! */ - case MACRO_BYTOFF: -#ifdef RELOC_OP_P - if (tokidx < ntok && tok[tokidx].X_op == O_lituse_bytoff) - tokidx++; -#endif - break; - - /* optional !lituse_jsr! */ - case MACRO_JSR: -#ifdef RELOC_OP_P - if (tokidx < ntok && tok[tokidx].X_op == O_lituse_jsr) - tokidx++; -#endif - break; - match_failed: while (*arg != MACRO_EOA) ++arg; @@ -2305,7 +2341,7 @@ find_macro_match (first_macro, tok, pntok) ++arg; } } - while (++macro - alpha_macros < alpha_num_macros + while (++macro - alpha_macros < (int) alpha_num_macros && !strcmp (macro->name, first_macro->name)); return NULL; @@ -2364,18 +2400,19 @@ insert_operand (insn, operand, val, file, line) return insn; } -/* - * Turn an opcode description and a set of arguments into - * an instruction and a fixup. - */ +/* Turn an opcode description and a set of arguments into + an instruction and a fixup. */ static void -assemble_insn (opcode, tok, ntok, insn) +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; @@ -2431,30 +2468,89 @@ assemble_insn (opcode, tok, ntok, insn) 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: - { - struct alpha_fixup *fixup; + /* This is only 0 for fields that should contain registers, + which means this pattern shouldn't have matched. */ + if (operand->default_reloc == 0) + abort (); - if (insn->nfixups >= MAX_INSN_FIXUPS) - as_fatal (_("too many fixups")); + /* There is one special case for which an insn receives two + relocations, and thus the user-supplied reloc does not + override the operand reloc. */ + if (operand->default_reloc == BFD_RELOC_ALPHA_HINT) + { + struct alpha_fixup *fixup; - fixup = &insn->fixups[insn->nfixups++]; + if (insn->nfixups >= MAX_INSN_FIXUPS) + as_fatal (_("too many fixups")); - fixup->exp = *t; - fixup->reloc = operand->default_reloc; - } + 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")); + + /* ??? My but this is hacky. But the OSF/1 assembler uses the same + relocation tag for both ldah and lda with gpdisp. Choose the + correct internal relocation based on the opcode. */ + if (reloc == BFD_RELOC_ALPHA_GPDISP) + { + if (strcmp (opcode->name, "ldah") == 0) + reloc = BFD_RELOC_ALPHA_GPDISP_HI16; + else if (strcmp (opcode->name, "lda") == 0) + reloc = BFD_RELOC_ALPHA_GPDISP_LO16; + else + as_bad (_("invalid relocation for instruction")); + } + + /* If this is a real relocation (as opposed to a lituse hint), then + the relocation width should match the operand width. */ + 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; } -/* - * Actually output an instruction with its fixup. - */ +/* Actually output an instruction with its fixup. */ static void emit_insn (insn) @@ -2478,62 +2574,40 @@ emit_insn (insn) dwarf2_emit_insn (4); #endif - /* Apply the fixups in order */ + /* Apply the fixups in order. */ for (i = 0; i < insn->nfixups; ++i) { const struct alpha_operand *operand = (const struct alpha_operand *) 0; struct alpha_fixup *fixup = &insn->fixups[i]; + struct alpha_reloc_tag *info = NULL; int size, pcrel; fixS *fixP; -#ifdef RELOC_OP_P - char buffer[ALPHA_RELOC_DIGITS]; - struct alpha_literal_tag *info; -#endif - /* Some fixups are only used internally and so have no howto */ + /* Some fixups are only used internally and so have no howto. */ if ((int) fixup->reloc < 0) { operand = &alpha_operands[-(int) fixup->reloc]; size = 4; pcrel = ((operand->flags & AXP_OPERAND_RELATIVE) != 0); } + else if (fixup->reloc > BFD_RELOC_UNUSED + || fixup->reloc == BFD_RELOC_ALPHA_GPDISP_HI16 + || fixup->reloc == BFD_RELOC_ALPHA_GPDISP_LO16) + { + size = 2; + pcrel = 0; + } else - switch (fixup->reloc) - { -#ifdef OBJ_ELF - /* These relocation types are only used internally. */ - case BFD_RELOC_ALPHA_GPDISP_HI16: - case BFD_RELOC_ALPHA_GPDISP_LO16: - size = 2; - pcrel = 0; - break; -#endif -#ifdef RELOC_OP_P - /* and these also are internal only relocations */ - case BFD_RELOC_ALPHA_USER_LITERAL: - case BFD_RELOC_ALPHA_USER_LITUSE_BASE: - case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF: - case BFD_RELOC_ALPHA_USER_LITUSE_JSR: - case BFD_RELOC_ALPHA_USER_GPDISP: - case BFD_RELOC_ALPHA_USER_GPRELHIGH: - case BFD_RELOC_ALPHA_USER_GPRELLOW: - size = 2; - pcrel = 0; - break; -#endif + { + reloc_howto_type *reloc_howto + = bfd_reloc_type_lookup (stdoutput, fixup->reloc); + assert (reloc_howto); - default: - { - 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); - size = bfd_get_reloc_size (reloc_howto); - pcrel = reloc_howto->pc_relative; - } - assert (size >= 1 && size <= 4); - break; - } + pcrel = reloc_howto->pc_relative; + } fixP = fix_new_exp (frag_now, f - frag_now->fr_literal, size, &fixup->exp, pcrel, fixup->reloc); @@ -2542,80 +2616,139 @@ emit_insn (insn) and copy in the sequence number for the explicit relocations. */ switch (fixup->reloc) { - case BFD_RELOC_ALPHA_GPDISP_LO16: -#ifdef OBJ_ECOFF - case BFD_RELOC_ALPHA_LITERAL: -#endif -#ifdef OBJ_ELF - case BFD_RELOC_ALPHA_ELF_LITERAL: -#endif + 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; -#ifdef RELOC_OP_P - case BFD_RELOC_ALPHA_USER_LITERAL: + case BFD_RELOC_ALPHA_GPDISP_HI16: fixP->fx_no_overflow = 1; - sprintf (buffer, "!%u", insn->sequence[i]); - info = ((struct alpha_literal_tag *) - hash_find (alpha_literal_hash, buffer)); + fixP->fx_addsy = section_symbol (now_seg); + fixP->fx_offset = 0; - if (! info) - { - size_t len = strlen (buffer); - const char *errmsg; - - info = ((struct alpha_literal_tag *) - xcalloc (sizeof (struct alpha_literal_tag) + len, 1)); - - info->segment = now_seg; - info->sequence = insn->sequence[i]; - strcpy (info->string, buffer); - errmsg = hash_insert (alpha_literal_hash, info->string, (PTR) info); - if (errmsg) - as_bad (errmsg); - } + info = 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; - ++info->n_literals; + 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) - info->multi_section_p = 1; - + 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_USER_LITUSE_BASE: - case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF: - case BFD_RELOC_ALPHA_USER_LITUSE_JSR: - sprintf (buffer, "!%u", insn->sequence[i]); - info = ((struct alpha_literal_tag *) - hash_find (alpha_literal_hash, buffer)); + 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; - if (! info) +#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) { - size_t len = strlen (buffer); - const char *errmsg; - - info = ((struct alpha_literal_tag *) - xcalloc (sizeof (struct alpha_literal_tag) + len, 1)); - - info->segment = now_seg; - info->sequence = insn->sequence[i]; - strcpy (info->string, buffer); - errmsg = hash_insert (alpha_literal_hash, info->string, (PTR) info); - if (errmsg) - as_bad (errmsg); + 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); } - info->n_lituses++; fixP->tc_fix_data.info = info; - fixP->tc_fix_data.next_lituse = info->lituse; - info->lituse = fixP; + 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) { @@ -2650,7 +2783,7 @@ assemble_tokens_to_insn (opname, tok, ntok, insn) opcode = find_opcode_match (opcode, tok, &ntok, &cpumatch); if (opcode) { - assemble_insn (opcode, tok, ntok, insn); + assemble_insn (opcode, tok, ntok, insn, BFD_RELOC_UNUSED); return; } else if (cpumatch) @@ -2677,8 +2810,17 @@ assemble_tokens (opname, tok, ntok, local_macros_on) const struct alpha_opcode *opcode; const struct alpha_macro *macro; int cpumatch = 1; + bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED; - /* search macros */ +#ifdef RELOC_OP_P + /* If a user-specified relocation is present, this is not a macro. */ + if (ntok && USER_RELOC_P (tok[ntok - 1].X_op)) + { + reloc = ALPHA_RELOC_TABLE (tok[ntok - 1].X_op)->reloc; + ntok--; + } + else +#endif if (local_macros_on) { macro = ((const struct alpha_macro *) @@ -2695,18 +2837,7 @@ assemble_tokens (opname, tok, ntok, local_macros_on) } } -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok - 1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok - 1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int) reloc_exp->X_add_number, opname); - ntok--; - } -#endif - - /* search opcodes */ + /* Search opcodes. */ opcode = (const struct alpha_opcode *) hash_find (alpha_opcode_hash, opname); if (opcode) { @@ -2715,23 +2846,30 @@ assemble_tokens (opname, tok, ntok, local_macros_on) if (opcode) { struct alpha_insn insn; - assemble_insn (opcode, tok, ntok, &insn); + assemble_insn (opcode, tok, ntok, &insn, reloc); + + /* Copy the sequence number for the reloc from the reloc token. */ + if (reloc != BFD_RELOC_UNUSED) + insn.sequence = tok[ntok].X_add_number; + emit_insn (&insn); return; } } if (found_something) - if (cpumatch) - as_bad (_("inappropriate arguments for opcode `%s'"), opname); - else - as_bad (_("opcode `%s' not supported for target %s"), opname, - alpha_target_name); + { + 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); } -/* Some instruction sets indexed by lg(size) */ +/* Some instruction sets indexed by lg(size). */ static const char * const sextX_op[] = { "sextb", "sextw", "sextl", NULL }; static const char * const insXl_op[] = { "insbl", "inswl", "insll", "insql" }; static const char * const insXh_op[] = { NULL, "inswh", "inslh", "insqh" }; @@ -2740,7 +2878,6 @@ 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 ldX_op[] = { "ldb", "ldw", "ldll", "ldq" }; static const char * const ldXu_op[] = { "ldbu", "ldwu", NULL, NULL }; /* Implement the ldgp macro. */ @@ -2761,17 +2898,6 @@ FIXME expressionS newtok[3]; expressionS addend; -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok - 1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok - 1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int) reloc_exp->X_add_number, "ldgp"); - ntok--; - } -#endif - #ifdef OBJ_ECOFF if (regno (tok[2].X_add_number) == AXP_REG_PV) ecoff_set_gp_prolog_size (0); @@ -2795,6 +2921,7 @@ FIXME 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); @@ -2809,6 +2936,7 @@ FIXME insn.nfixups = 1; insn.fixups[0].exp = addend; insn.fixups[0].reloc = BFD_RELOC_ALPHA_GPDISP_LO16; + insn.sequence = next_sequence_num--; emit_insn (&insn); #endif /* OBJ_ECOFF || OBJ_ELF */ @@ -2888,18 +3016,18 @@ add_to_link_pool (basesym, sym, addend) If explicit relocations of the form !literal! are allowed, and used, then explict_reloc with be an expression pointer. - Finally, the return value is true if the calling macro may emit a - LITUSE reloc if otherwise appropriate. */ + Finally, the return value is nonzero if the calling macro may emit + a LITUSE reloc if otherwise appropriate; the return value is the + sequence number to use. */ -static int -load_expression (targreg, exp, pbasereg, poffset, explicit_reloc) +static long +load_expression (targreg, exp, pbasereg, poffset) int targreg; const expressionS *exp; int *pbasereg; expressionS *poffset; - const expressionS *explicit_reloc; { - int emit_lituse = 0; + long emit_lituse = 0; offsetT addend = exp->X_add_number; int basereg = *pbasereg; struct alpha_insn insn; @@ -2912,7 +3040,7 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc) #ifdef OBJ_ECOFF offsetT lit; - /* attempt to reduce .lit load by splitting the offset from + /* Attempt to reduce .lit load by splitting the offset from its symbol when possible, but don't create a situation in which we'd fail. */ if (!range_signed_32 (addend) && @@ -2949,9 +3077,9 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc) assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - assert (explicit_reloc == (const expressionS *) 0); assert (insn.nfixups == 1); insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL; + insn.sequence = emit_lituse = next_sequence_num--; #endif /* OBJ_ECOFF */ #ifdef OBJ_ELF /* emit "ldq r, gotoff(gp)" */ @@ -2988,25 +3116,14 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc) assemble_tokens_to_insn ("ldq", newtok, 3, &insn); assert (insn.nfixups == 1); - if (!explicit_reloc) - insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL; - else - { -#ifdef RELOC_OP_P - insn.fixups[0].reloc - = (ALPHA_RELOC_TABLE (explicit_reloc->X_op))->reloc; - insn.sequence[0] = explicit_reloc->X_add_number; -#else - abort (); -#endif - } + insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL; + insn.sequence = emit_lituse = next_sequence_num--; #endif /* OBJ_ELF */ #ifdef OBJ_EVAX offsetT link; /* Find symbol or symbol pointer in link section. */ - assert (explicit_reloc == (const expressionS *) 0); if (exp->X_add_symbol == alpha_evax_proc.symbol) { if (range_signed_16 (addend)) @@ -3048,8 +3165,6 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc) emit_insn (&insn); #ifndef OBJ_EVAX - emit_lituse = 1; - if (basereg != alpha_gp_register && basereg != AXP_REG_ZERO) { /* emit "addq r, base, r" */ @@ -3065,14 +3180,12 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc) break; case O_constant: - assert (explicit_reloc == (const expressionS *) 0); break; case O_subtract: /* Assume that this difference expression will be resolved to an absolute value and that that value will fit in 16 bits. */ - assert (explicit_reloc == (const expressionS *) 0); set_tok_reg (newtok[0], targreg); newtok[1] = *exp; set_tok_preg (newtok[2], basereg); @@ -3099,8 +3212,9 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc) if (!range_signed_32 (addend)) { offsetT lit; + long seq_num = next_sequence_num--; - /* for 64-bit addends, just put it in the literal pool */ + /* For 64-bit addends, just put it in the literal pool. */ #ifdef OBJ_EVAX /* emit "ldq targreg, lit(basereg)" */ @@ -3160,6 +3274,7 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc) #ifdef OBJ_ELF insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL; #endif + insn.sequence = seq_num; emit_insn (&insn); @@ -3171,16 +3286,10 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc) assemble_tokens_to_insn ("ldq", newtok, 3, &insn); assert (insn.nfixups < MAX_INSN_FIXUPS); - if (insn.nfixups > 0) - { - memmove (&insn.fixups[1], &insn.fixups[0], - sizeof (struct alpha_fixup) * insn.nfixups); - } + insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE; + insn.fixups[insn.nfixups].exp.X_op = O_absent; insn.nfixups++; - insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE; - insn.fixups[0].exp.X_op = O_symbol; - insn.fixups[0].exp.X_add_symbol = section_symbol (now_seg); - insn.fixups[0].exp.X_add_number = LITUSE_BASE; + insn.sequence = seq_num; emit_lituse = 0; emit_insn (&insn); @@ -3260,66 +3369,19 @@ load_expression (targreg, exp, pbasereg, poffset, explicit_reloc) large constants. */ static void -emit_lda (tok, ntok, opname) +emit_lda (tok, ntok, unused) const expressionS *tok; int ntok; - const PTR opname; + const PTR unused ATTRIBUTE_UNUSED; { int basereg; - const expressionS *reloc = (const expressionS *) 0; - -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok - 1].X_op)) - { - const struct alpha_reloc_op_tag *r; - - reloc = &tok[ntok - 1]; - r = ALPHA_RELOC_TABLE (reloc->X_op); - switch (reloc->X_op) - { - default: - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int) reloc->X_add_number, (const char *) opname); - - reloc = (const expressionS *) 0; - ntok--; - break; - - case O_literal: - ntok--; - break; - - /* For lda $x,0($x)!lituse_base!y, don't use load_expression, since - it is really too general for our needs. Instead just generate the - lda directly. */ - case O_lituse_base: - if (ntok != 4 - || tok[0].X_op != O_register - || !is_ir_num (tok[0].X_add_number) - || tok[1].X_op != O_constant - || tok[2].X_op != O_pregister - || !is_ir_num (tok[2].X_add_number)) - { - as_bad (_("bad instruction format for lda !%s!%ld"), r->name, - (long) reloc->X_add_number); - - reloc = (const expressionS *) 0; - ntok--; - break; - } - - emit_loadstore (tok, ntok, "lda"); - return; - } - } -#endif if (ntok == 2) basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register); else basereg = tok[2].X_add_number; - (void) load_expression (tok[0].X_add_number, &tok[1], &basereg, NULL, reloc); + (void) load_expression (tok[0].X_add_number, &tok[1], &basereg, NULL); } /* The ldah macro differs from the ldah instruction in that it has $31 @@ -3333,17 +3395,6 @@ emit_ldah (tok, ntok, unused) { expressionS newtok[3]; -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok - 1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok - 1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int) reloc_exp->X_add_number, "ldah"); - ntok--; - } -#endif - newtok[0] = tok[0]; newtok[1] = tok[1]; set_tok_preg (newtok[2], AXP_REG_ZERO); @@ -3361,83 +3412,31 @@ emit_ir_load (tok, ntok, opname) int ntok; const PTR opname; { - int basereg, lituse; + int basereg; + long lituse; expressionS newtok[3]; struct alpha_insn insn; -#ifdef RELOC_OP_P - const expressionS *reloc = (const expressionS *) 0; - - if (ntok && USER_RELOC_P (tok[ntok - 1].X_op)) - { - const struct alpha_reloc_op_tag *r; - - reloc = &tok[ntok - 1]; - switch (reloc->X_op) - { - case O_lituse_base: - ntok--; - break; - - case O_literal: - if (strcmp ((const char *) opname, "ldq") == 0) - { - emit_lda (tok, ntok, opname); - return; - } - - /* fall through */ - default: - ntok--; - r = ALPHA_RELOC_TABLE (reloc->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int) reloc->X_add_number, (const char *) opname); - } - } -#endif - if (ntok == 2) basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register); else basereg = tok[2].X_add_number; lituse = load_expression (tok[0].X_add_number, &tok[1], &basereg, - &newtok[1], (const expressionS *) 0); + &newtok[1]); newtok[0] = tok[0]; set_tok_preg (newtok[2], basereg); assemble_tokens_to_insn ((const char *) opname, newtok, 3, &insn); -#ifdef RELOC_OP_P - if (reloc) - { - int nfixups = insn.nfixups; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc->X_op); - - assert (nfixups < MAX_INSN_FIXUPS); - insn.fixups[nfixups].reloc = r->reloc; - insn.fixups[nfixups].exp.X_op = O_symbol; - insn.fixups[nfixups].exp.X_add_symbol = section_symbol (now_seg); - insn.fixups[nfixups].exp.X_add_number = r->lituse; - insn.sequence[nfixups] = reloc->X_add_number; - insn.nfixups++; - } -#endif - if (lituse) { assert (insn.nfixups < MAX_INSN_FIXUPS); - if (insn.nfixups > 0) - { - memmove (&insn.fixups[1], &insn.fixups[0], - sizeof (struct alpha_fixup) * insn.nfixups); - } + insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE; + insn.fixups[insn.nfixups].exp.X_op = O_absent; insn.nfixups++; - insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE; - insn.fixups[0].exp.X_op = O_symbol; - insn.fixups[0].exp.X_add_symbol = section_symbol (now_seg); - insn.fixups[0].exp.X_add_number = LITUSE_BASE; + insn.sequence = lituse; } emit_insn (&insn); @@ -3452,25 +3451,11 @@ emit_loadstore (tok, ntok, opname) int ntok; const PTR opname; { - int basereg, lituse; + int basereg; + long lituse; expressionS newtok[3]; struct alpha_insn insn; -#ifdef RELOC_OP_P - const expressionS *reloc = (const expressionS *) 0; - - if (ntok && USER_RELOC_P (tok[ntok - 1].X_op)) - { - reloc = &tok[--ntok]; - if (reloc->X_op != O_lituse_base) - { - const struct alpha_reloc_op_tag *r = &alpha_reloc_op[reloc->X_md]; - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int) reloc->X_add_number, (const char *) opname); - } - } -#endif - if (ntok == 2) basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register); else @@ -3481,8 +3466,7 @@ emit_loadstore (tok, ntok, opname) if (alpha_noat_on) as_bad (_("macro requires $at register while noat in effect")); - lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, &newtok[1], - (const expressionS *) 0); + lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, &newtok[1]); } else { @@ -3490,40 +3474,18 @@ emit_loadstore (tok, ntok, opname) lituse = 0; } - newtok[0] = tok[0]; - set_tok_preg (newtok[2], basereg); - - assemble_tokens_to_insn ((const char *) opname, newtok, 3, &insn); - -#ifdef RELOC_OP_P - if (reloc) - { - int nfixups = insn.nfixups; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc->X_op); - - assert (nfixups < MAX_INSN_FIXUPS); - insn.fixups[nfixups].reloc = r->reloc; - insn.fixups[nfixups].exp.X_op = O_symbol; - insn.fixups[nfixups].exp.X_add_symbol = section_symbol (now_seg); - insn.fixups[nfixups].exp.X_add_number = r->lituse; - insn.sequence[nfixups] = reloc->X_add_number; - insn.nfixups++; - } -#endif - + 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); - if (insn.nfixups > 0) - { - memmove (&insn.fixups[1], &insn.fixups[0], - sizeof (struct alpha_fixup) * insn.nfixups); - } + insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE; + insn.fixups[insn.nfixups].exp.X_op = O_absent; insn.nfixups++; - insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE; - insn.fixups[0].exp.X_op = O_symbol; - insn.fixups[0].exp.X_add_symbol = section_symbol (now_seg); - insn.fixups[0].exp.X_add_number = LITUSE_BASE; + insn.sequence = lituse; } emit_insn (&insn); @@ -3542,41 +3504,57 @@ emit_ldXu (tok, ntok, vlgsize) else { expressionS newtok[3]; - -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok - 1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok - 1]; - const struct alpha_reloc_op_tag *r - = ALPHA_RELOC_TABLE (reloc_exp->X_op); - - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int) reloc_exp->X_add_number, "ldbu/ldwu"); - ntok--; - } -#endif + struct alpha_insn insn; + int basereg; + long lituse; if (alpha_noat_on) as_bad (_("macro requires $at register while noat in effect")); + if (ntok == 2) + basereg = (tok[1].X_op == O_constant + ? AXP_REG_ZERO : alpha_gp_register); + else + basereg = tok[2].X_add_number; + /* emit "lda $at, exp" */ - memcpy (newtok, tok, sizeof (expressionS) * ntok); - newtok[0].X_add_number = AXP_REG_AT; - assemble_tokens ("lda", newtok, ntok, 1); + lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL); /* emit "ldq_u targ, 0($at)" */ newtok[0] = tok[0]; set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], AXP_REG_AT); - assemble_tokens ("ldq_u", newtok, 3, 1); + 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); /* emit "extXl targ, $at, targ" */ - set_tok_reg (newtok[1], AXP_REG_AT); + set_tok_reg (newtok[1], basereg); newtok[2] = newtok[0]; - assemble_tokens (extXl_op[(long) vlgsize], newtok, 3, 1); + 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); } } @@ -3671,17 +3649,6 @@ emit_ldil (tok, ntok, unused) { expressionS newtok[2]; -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok - 1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok - 1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int) reloc_exp->X_add_number, "ldil"); - ntok--; - } -#endif - memcpy (newtok, tok, sizeof (newtok)); newtok[1].X_add_number = sign_extend_32 (tok[1].X_add_number); @@ -3703,35 +3670,75 @@ emit_stX (tok, ntok, vlgsize) else { expressionS newtok[3]; + struct alpha_insn insn; + int basereg; + long lituse; if (alpha_noat_on) as_bad (_("macro requires $at register while noat in effect")); + if (ntok == 2) + basereg = (tok[1].X_op == O_constant + ? AXP_REG_ZERO : alpha_gp_register); + else + basereg = tok[2].X_add_number; + /* emit "lda $at, exp" */ - memcpy (newtok, tok, sizeof (expressionS) * ntok); - newtok[0].X_add_number = AXP_REG_AT; - assemble_tokens ("lda", newtok, ntok, 1); + lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL); /* emit "ldq_u $t9, 0($at)" */ set_tok_reg (newtok[0], AXP_REG_T9); set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], AXP_REG_AT); - assemble_tokens ("ldq_u", newtok, 3, 1); + 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); /* emit "insXl src, $at, $t10" */ newtok[0] = tok[0]; - set_tok_reg (newtok[1], AXP_REG_AT); + set_tok_reg (newtok[1], basereg); set_tok_reg (newtok[2], AXP_REG_T10); - assemble_tokens (insXl_op[lgsize], newtok, 3, 1); + 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); /* emit "mskXl $t9, $at, $t9" */ set_tok_reg (newtok[0], AXP_REG_T9); newtok[2] = newtok[0]; - assemble_tokens (mskXl_op[lgsize], newtok, 3, 1); + 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); /* emit "or $t9, $t10, $t9" */ @@ -3740,9 +3747,20 @@ emit_stX (tok, ntok, vlgsize) /* emit "stq_u $t9, 0($at) */ - set_tok_const (newtok[1], 0); + set_tok_const(newtok[1], 0); set_tok_preg (newtok[2], AXP_REG_AT); - assemble_tokens ("stq_u", newtok, 3, 1); + 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); } } @@ -3846,19 +3864,6 @@ emit_sextX (tok, ntok, vlgsize) int bitshift = 64 - 8 * (1 << lgsize); expressionS newtok[3]; -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok - 1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok - 1]; - const struct alpha_reloc_op_tag *r - = ALPHA_RELOC_TABLE (reloc_exp->X_op); - - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int) reloc_exp->X_add_number, "setxt"); - ntok--; - } -#endif - /* emit "sll src,bits,dst" */ newtok[0] = tok[0]; @@ -3887,35 +3892,23 @@ emit_division (tok, ntok, symname) const PTR symname; { /* DIVISION and MODULUS. Yech. - * - * Convert - * OP x,y,result - * to - * mov x,R16 # if x != R16 - * mov y,R17 # if y != R17 - * lda AT,__OP - * jsr AT,(AT),0 - * mov R0,result - * - * with appropriate optimizations if R0,R16,R17 are the registers - * specified by the compiler. - */ + + Convert + OP x,y,result + to + mov x,R16 # if x != R16 + mov y,R17 # if y != R17 + lda AT,__OP + jsr AT,(AT),0 + mov R0,result + + with appropriate optimizations if R0,R16,R17 are the registers + specified by the compiler. */ int xr, yr, rr; symbolS *sym; expressionS newtok[3]; -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok - 1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok - 1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int) reloc_exp->X_add_number, (char char *) symname); - ntok--; - } -#endif - xr = regno (tok[0].X_add_number); yr = regno (tok[1].X_add_number); @@ -3924,10 +3917,10 @@ emit_division (tok, ntok, symname) else rr = regno (tok[2].X_add_number); - /* Move the operands into the right place */ + /* Move the operands into the right place. */ if (yr == AXP_REG_R16 && xr == AXP_REG_R17) { - /* They are in exactly the wrong order -- swap through AT */ + /* They are in exactly the wrong order -- swap through AT. */ if (alpha_noat_on) as_bad (_("macro requires $at register while noat in effect")); @@ -3974,13 +3967,13 @@ emit_division (tok, ntok, symname) set_tok_sym (newtok[1], sym, 0); assemble_tokens ("lda", newtok, 2, 1); - /* Call the division routine */ + /* Call the division routine. */ set_tok_reg (newtok[0], AXP_REG_AT); set_tok_cpreg (newtok[1], AXP_REG_AT); set_tok_const (newtok[2], 0); assemble_tokens ("jsr", newtok, 3, 1); - /* Move the result to the right place */ + /* Move the result to the right place. */ if (rr != AXP_REG_R0) { set_tok_reg (newtok[0], AXP_REG_R0); @@ -3998,34 +3991,22 @@ emit_division (tok, ntok, symname) const PTR symname; { /* DIVISION and MODULUS. Yech. - * Convert - * OP x,y,result - * to - * lda pv,__OP - * mov x,t10 - * mov y,t11 - * jsr t9,(pv),__OP - * mov t12,result - * - * with appropriate optimizations if t10,t11,t12 are the registers - * specified by the compiler. - */ + Convert + OP x,y,result + to + lda pv,__OP + mov x,t10 + mov y,t11 + jsr t9,(pv),__OP + mov t12,result + + with appropriate optimizations if t10,t11,t12 are the registers + specified by the compiler. */ int xr, yr, rr; symbolS *sym; expressionS newtok[3]; -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok - 1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok - 1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int) reloc_exp->X_add_number, (const char *) symname); - ntok--; - } -#endif - xr = regno (tok[0].X_add_number); yr = regno (tok[1].X_add_number); @@ -4036,11 +4017,10 @@ emit_division (tok, ntok, symname) sym = symbol_find_or_make ((const char *) symname); - /* Move the operands into the right place */ + /* Move the operands into the right place. */ if (yr == AXP_REG_T10 && xr == AXP_REG_T11) { - /* They are in exactly the wrong order -- swap through AT */ - + /* They are in exactly the wrong order -- swap through AT. */ if (alpha_noat_on) as_bad (_("macro requires $at register while noat in effect")); @@ -4080,12 +4060,12 @@ emit_division (tok, ntok, symname) } } - /* Call the division routine */ + /* Call the division routine. */ set_tok_reg (newtok[0], AXP_REG_T9); set_tok_sym (newtok[1], sym, 0); assemble_tokens ("jsr", newtok, 2, 1); - /* Reload the GP register */ + /* Reload the GP register. */ #ifdef OBJ_AOUT FIXME #endif @@ -4096,7 +4076,7 @@ FIXME assemble_tokens ("ldgp", newtok, 3, 1); #endif - /* Move the result to the right place */ + /* Move the result to the right place. */ if (rr != AXP_REG_T12) { set_tok_reg (newtok[0], AXP_REG_T12); @@ -4120,18 +4100,8 @@ emit_jsrjmp (tok, ntok, vopname) const char *opname = (const char *) vopname; struct alpha_insn insn; expressionS newtok[3]; - int r, tokidx = 0, lituse = 0; - -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok - 1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok - 1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int) reloc_exp->X_add_number, opname); - ntok--; - } -#endif + int r, tokidx = 0; + long lituse = 0; if (tokidx < ntok && tok[tokidx].X_op == O_register) r = regno (tok[tokidx++].X_add_number); @@ -4149,8 +4119,7 @@ emit_jsrjmp (tok, ntok, vopname) else { int basereg = alpha_gp_register; - lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], &basereg, NULL, - (const expressionS *) 0); + lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], &basereg, NULL); } #endif @@ -4167,20 +4136,13 @@ emit_jsrjmp (tok, ntok, vopname) assemble_tokens_to_insn (opname, newtok, 3, &insn); - /* add the LITUSE fixup */ if (lituse) { assert (insn.nfixups < MAX_INSN_FIXUPS); - if (insn.nfixups > 0) - { - memmove (&insn.fixups[1], &insn.fixups[0], - sizeof (struct alpha_fixup) * insn.nfixups); - } + insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_JSR; + insn.fixups[insn.nfixups].exp.X_op = O_absent; insn.nfixups++; - insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE; - insn.fixups[0].exp.X_op = O_symbol; - insn.fixups[0].exp.X_add_symbol = section_symbol (now_seg); - insn.fixups[0].exp.X_add_number = LITUSE_JSR; + insn.sequence = lituse; } emit_insn (&insn); @@ -4199,17 +4161,6 @@ emit_retjcr (tok, ntok, vopname) expressionS newtok[3]; int r, tokidx = 0; -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok - 1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok - 1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int) reloc_exp->X_add_number, opname); - ntok--; - } -#endif - if (tokidx < ntok && tok[tokidx].X_op == O_register) r = regno (tok[tokidx++].X_add_number); else @@ -4233,7 +4184,7 @@ emit_retjcr (tok, ntok, vopname) assemble_tokens (opname, newtok, 3, 0); } -/* Assembler directives */ +/* Assembler directives. */ /* Handle the .text pseudo-op. This is like the usual one, but it clears alpha_insn_label and restores auto alignment. */ @@ -4243,7 +4194,11 @@ 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; @@ -4256,7 +4211,11 @@ 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; @@ -4269,7 +4228,7 @@ s_alpha_data (i) static void s_alpha_comm (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { register char *name; register char c; @@ -4385,7 +4344,7 @@ s_alpha_comm (ignore) static void s_alpha_rdata (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { int temp; @@ -4406,7 +4365,7 @@ s_alpha_rdata (ignore) static void s_alpha_sdata (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { int temp; @@ -4420,13 +4379,32 @@ s_alpha_sdata (ignore) #endif #ifdef OBJ_ELF +struct alpha_elf_frame_data +{ + symbolS *func_sym; + symbolS *func_end_sym; + symbolS *prologue_sym; + unsigned int mask; + unsigned int fmask; + int fp_regno; + int ra_regno; + offsetT frame_size; + offsetT mask_offset; + offsetT fmask_offset; + + struct alpha_elf_frame_data *next; +}; + +static struct alpha_elf_frame_data *all_frame_data; +static struct alpha_elf_frame_data **plast_frame_data = &all_frame_data; +static struct alpha_elf_frame_data *cur_frame_data; /* Handle the .section pseudo-op. This is like the usual one, but it clears alpha_insn_label and restores auto alignment. */ static void s_alpha_section (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { obj_elf_section (ignore); @@ -4456,12 +4434,21 @@ s_alpha_ent (dummy) { symbolS *sym; - if (alpha_cur_ent_sym) + if (cur_frame_data) as_warn (_("nested .ent directives")); sym = symbol_find_or_make (name); symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION; - alpha_cur_ent_sym = sym; + + cur_frame_data = calloc (1, sizeof (*cur_frame_data)); + cur_frame_data->func_sym = sym; + + /* Provide sensible defaults. */ + cur_frame_data->fp_regno = 30; /* sp */ + cur_frame_data->ra_regno = 26; /* ra */ + + *plast_frame_data = cur_frame_data; + plast_frame_data = &cur_frame_data->next; /* The .ent directive is sometimes followed by a number. Not sure what it really means, but ignore it. */ @@ -4472,7 +4459,7 @@ s_alpha_ent (dummy) input_line_pointer++; SKIP_WHITESPACE (); } - if (isdigit (*input_line_pointer) || *input_line_pointer == '-') + if (ISDIGIT (*input_line_pointer) || *input_line_pointer == '-') (void) get_absolute_expression (); } demand_empty_rest_of_line (); @@ -4501,22 +4488,27 @@ s_alpha_end (dummy) symbolS *sym; sym = symbol_find (name); - if (sym != alpha_cur_ent_sym) + if (!cur_frame_data) + as_warn (_(".end directive without matching .ent")); + else if (sym != cur_frame_data->func_sym) as_warn (_(".end directive names different symbol than .ent")); /* Create an expression to calculate the size of the function. */ if (sym) { - symbol_get_obj (sym)->size = - (expressionS *) xmalloc (sizeof (expressionS)); - symbol_get_obj (sym)->size->X_op = O_subtract; - symbol_get_obj (sym)->size->X_add_symbol - = symbol_new ("L0\001", now_seg, frag_now_fix (), frag_now); - symbol_get_obj (sym)->size->X_op_symbol = sym; - symbol_get_obj (sym)->size->X_add_number = 0; + 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; } - alpha_cur_ent_sym = NULL; + cur_frame_data = NULL; *input_line_pointer = name_end; } @@ -4536,7 +4528,45 @@ s_alpha_mask (fp) ecoff_directive_mask (0); } else - discard_rest_of_line (); + { + 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 @@ -4546,7 +4576,36 @@ s_alpha_frame (dummy) if (ECOFF_DEBUGGING) ecoff_directive_frame (0); else - discard_rest_of_line (); + { + long val; + + if (!cur_frame_data) + { + as_warn (_(".frame outside of .ent")); + discard_rest_of_line (); + return; + } + + cur_frame_data->fp_regno = tc_get_register (1); + + SKIP_WHITESPACE (); + if (*input_line_pointer++ != ',' + || get_absolute_expression_and_terminator (&val) != ',') + { + as_warn (_("bad .frame directive")); + --input_line_pointer; + discard_rest_of_line (); + return; + } + cur_frame_data->frame_size = val; + + cur_frame_data->ra_regno = tc_get_register (0); + + /* Next comes the "offset of saved $a0 from $sp". In gcc terms + this is current_function_pretend_args_size. There's no place + to put this value, so ignore it. */ + s_ignore (42); + } } static void @@ -4562,8 +4621,13 @@ s_alpha_prologue (ignore) if (ECOFF_DEBUGGING) sym = ecoff_get_cur_proc_sym (); else - sym = alpha_cur_ent_sym; - know (sym != NULL); + 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) { @@ -4582,6 +4646,9 @@ s_alpha_prologue (ignore) 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; @@ -4675,8 +4742,146 @@ s_alpha_coff_wrapper (which) ignore_rest_of_line (); } } + +/* Called at the end of assembly. Here we emit unwind info for frames + unless the compiler has done it for us. */ + +void +alpha_elf_md_end (void) +{ + struct alpha_elf_frame_data *p; + + if (cur_frame_data) + as_warn (_(".ent directive without matching .end")); + + /* If someone has generated the unwind info themselves, great. */ + if (bfd_get_section_by_name (stdoutput, ".eh_frame") != NULL) + return; + + /* Generate .eh_frame data for the unwind directives specified. */ + for (p = all_frame_data; p ; p = p->next) + if (p->prologue_sym) + { + /* Create a temporary symbol at the same location as our + function symbol. This prevents problems with globals. */ + cfi_new_fde (symbol_temp_new (S_GET_SEGMENT (p->func_sym), + S_GET_VALUE (p->func_sym), + symbol_get_frag (p->func_sym))); + + cfi_set_return_column (p->ra_regno); + cfi_add_CFA_def_cfa_register (30); + if (p->fp_regno != 30 || p->mask || p->fmask || p->frame_size) + { + unsigned int mask; + offsetT offset; + + cfi_add_advance_loc (p->prologue_sym); + + if (p->fp_regno != 30) + if (p->frame_size != 0) + cfi_add_CFA_def_cfa (p->fp_regno, p->frame_size); + else + cfi_add_CFA_def_cfa_register (p->fp_regno); + else if (p->frame_size != 0) + cfi_add_CFA_def_cfa_offset (p->frame_size); + + mask = p->mask; + offset = p->mask_offset; + + /* Recall that $26 is special-cased and stored first. */ + if ((mask >> 26) & 1) + { + cfi_add_CFA_offset (26, offset); + offset += 8; + mask &= ~(1 << 26); + } + while (mask) + { + unsigned int i; + i = mask & -mask; + mask ^= i; + i = ffs (i) - 1; + + cfi_add_CFA_offset (i, offset); + offset += 8; + } + + mask = p->fmask; + offset = p->fmask_offset; + while (mask) + { + unsigned int i; + i = mask & -mask; + mask ^= i; + i = ffs (i) - 1; + + cfi_add_CFA_offset (i + 32, offset); + offset += 8; + } + } + + cfi_end_fde (p->func_end_sym); + } +} + +static void +s_alpha_usepv (int unused ATTRIBUTE_UNUSED) +{ + char *name, name_end; + char *which, which_end; + symbolS *sym; + int other; + + name = input_line_pointer; + name_end = get_symbol_end (); + + if (! is_name_beginner (*name)) + { + as_bad (_(".usepv directive has no name")); + *input_line_pointer = name_end; + ignore_rest_of_line (); + return; + } + + sym = symbol_find_or_make (name); + *input_line_pointer++ = name_end; + + if (name_end != ',') + { + as_bad (_(".usepv directive has no type")); + ignore_rest_of_line (); + return; + } + + SKIP_WHITESPACE (); + which = input_line_pointer; + which_end = get_symbol_end (); + + if (strcmp (which, "no") == 0) + other = STO_ALPHA_NOPV; + else if (strcmp (which, "std") == 0) + other = STO_ALPHA_STD_GPLOAD; + else + { + as_bad (_("unknown argument for .usepv")); + other = 0; + } + + *input_line_pointer = which_end; + demand_empty_rest_of_line (); + + S_SET_OTHER (sym, other | (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD)); +} #endif /* OBJ_ELF */ +/* Standard calling conventions leaves the CFA at $30 on entry. */ + +void +alpha_cfi_frame_initial_instructions () +{ + cfi_add_CFA_def_cfa_register (30); +} + #ifdef OBJ_EVAX /* Handle the section specific pseudo-op. */ @@ -4708,7 +4913,7 @@ s_alpha_section (secid) static void s_alpha_ent (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { symbolS *symbol; expressionS symexpr; @@ -4745,7 +4950,7 @@ s_alpha_ent (ignore) static void s_alpha_frame (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { long val; @@ -4779,7 +4984,7 @@ s_alpha_frame (ignore) static void s_alpha_pdesc (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { char *name; char name_end; @@ -4932,7 +5137,7 @@ s_alpha_pdesc (ignore) static void s_alpha_name (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { register char *p; expressionS exp; @@ -4970,7 +5175,7 @@ s_alpha_name (ignore) static void s_alpha_linkage (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { expressionS exp; char *p; @@ -4998,7 +5203,7 @@ s_alpha_linkage (ignore) static void s_alpha_code_address (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { expressionS exp; char *p; @@ -5026,7 +5231,7 @@ s_alpha_code_address (ignore) static void s_alpha_fp_save (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { alpha_evax_proc.fp_save = tc_get_register (1); @@ -5037,7 +5242,7 @@ s_alpha_fp_save (ignore) static void s_alpha_mask (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { long val; @@ -5058,7 +5263,7 @@ s_alpha_mask (ignore) static void s_alpha_fmask (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { long val; @@ -5079,7 +5284,7 @@ s_alpha_fmask (ignore) static void s_alpha_end (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { char c; @@ -5093,14 +5298,12 @@ s_alpha_end (ignore) static void s_alpha_file (ignore) - int ignore; + int ignore ATTRIBUTE_UNUSED; { symbolS *s; int length; static char case_hack[32]; - extern char *demand_copy_string PARAMS ((int *lenP)); - sprintf (case_hack, "", alpha_flag_hash_long_names, alpha_flag_show_after_trunc); @@ -5524,6 +5727,7 @@ const pseudo_typeS md_pseudo_table[] = { {"loc", s_alpha_loc, 9}, {"stabs", s_alpha_stab, 's'}, {"stabn", s_alpha_stab, 'n'}, + {"usepv", s_alpha_usepv, 0}, /* COFF debugging related pseudos. */ {"begin", s_alpha_coff_wrapper, 0}, {"bend", s_alpha_coff_wrapper, 1}, @@ -5613,6 +5817,7 @@ create_literal_section (name, secp, symp) /* @@@ GP selection voodoo. All of this seems overly complicated and unnecessary; which is the primary reason it's for ECOFF only. */ +static inline void maybe_set_gp PARAMS ((asection *)); static inline void maybe_set_gp (sec) @@ -5657,6 +5862,34 @@ select_gp_value () } #endif /* OBJ_ECOFF */ +#ifdef OBJ_ELF +/* Map 's' to SHF_ALPHA_GPREL. */ + +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; +} + +/* Map SHF_ALPHA_GPREL to SEC_SMALL_DATA. */ + +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 /* OBJ_ELF */ + /* Called internally to handle all alignment needs. This takes care of eliding calls to frag_align if'n the cached current alignment says we've already got it, as well as taking care of the auto-align @@ -5703,10 +5936,10 @@ void alpha_handle_align (fragp) fragS *fragp; { - static char const unop[4] = { 0x00, 0x00, 0xe0, 0x2f }; + static char const unop[4] = { 0x00, 0x00, 0xfe, 0x2f }; static char const nopunop[8] = { 0x1f, 0x04, 0xff, 0x47, - 0x00, 0x00, 0xe0, 0x2f + 0x00, 0x00, 0xfe, 0x2f }; int bytes, fix;