X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-alpha.c;h=f7656ec7ee253bb5ee71eb323b43cac0065b0f9c;hb=feb4bea70a297eb6316d1b0685bbbb8095b7fb29;hp=a5b35fc29add501afd6a25c988175c65d821267c;hpb=5a49b8acf456d4a049c002fae31b83a10b35e6f8;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-alpha.c b/gas/config/tc-alpha.c index a5b35fc29a..f7656ec7ee 100644 --- a/gas/config/tc-alpha.c +++ b/gas/config/tc-alpha.c @@ -1,6 +1,5 @@ /* tc-alpha.c - Processor-specific code for the DEC Alpha AXP CPU. - Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 1989-2016 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. @@ -57,9 +56,14 @@ #ifdef OBJ_ELF #include "elf/alpha.h" -#include "dwarf2dbg.h" #endif +#ifdef OBJ_EVAX +#include "vms.h" +#include "vms/egps.h" +#endif + +#include "dwarf2dbg.h" #include "dw2gencfi.h" #include "safe-ctype.h" @@ -70,10 +74,22 @@ #define MAX_INSN_FIXUPS 2 #define MAX_INSN_ARGS 5 +/* Used since new relocation types are introduced in this + file (DUMMY_RELOC_LITUSE_*) */ +typedef int extended_bfd_reloc_code_real_type; + struct alpha_fixup { expressionS exp; - bfd_reloc_code_real_type reloc; + /* bfd_reloc_code_real_type reloc; */ + extended_bfd_reloc_code_real_type reloc; +#ifdef OBJ_EVAX + /* The symbol of the item in the linkage section. */ + symbolS *xtrasym; + + /* The symbol of the procedure descriptor. */ + symbolS *procsym; +#endif }; struct alpha_insn @@ -92,7 +108,7 @@ enum alpha_macro_arg MACRO_OPIR, MACRO_CPIR, MACRO_FPR, - MACRO_EXP, + MACRO_EXP }; struct alpha_macro @@ -225,7 +241,7 @@ const char EXP_CHARS[] = "eE"; /* Characters which mean that a number is a floating point constant, as in 0d1.0. */ /* XXX: Do all of these really get used on the alpha?? */ -char FLT_CHARS[] = "rRsSfFdDxXpP"; +const char FLT_CHARS[] = "rRsSfFdDxXpP"; #ifdef OBJ_EVAX const char *md_shortopts = "Fm:g+1h:HG:"; @@ -244,6 +260,12 @@ struct option md_longopts[] = #define OPTION_NO_MDEBUG (OPTION_MDEBUG + 1) { "mdebug", no_argument, NULL, OPTION_MDEBUG }, { "no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG }, +#endif +#ifdef OBJ_EVAX +#define OPTION_REPLACE (OPTION_RELAX + 1) +#define OPTION_NOREPLACE (OPTION_REPLACE+1) + { "replace", no_argument, NULL, OPTION_REPLACE }, + { "noreplace", no_argument, NULL, OPTION_NOREPLACE }, #endif { NULL, no_argument, NULL, 0 } }; @@ -268,6 +290,7 @@ size_t md_longopts_size = sizeof (md_longopts); #undef AXP_REG_GP #define AXP_REG_GP AXP_REG_PV + #endif /* OBJ_EVAX */ /* The cpu for which we are generating code. */ @@ -299,11 +322,11 @@ static symbolS *alpha_register_table[64]; static segT alpha_lita_section; #endif #ifdef OBJ_EVAX -static segT alpha_link_section; -static segT alpha_ctors_section; -static segT alpha_dtors_section; +segT alpha_link_section; #endif +#ifndef OBJ_EVAX static segT alpha_lit8_section; +#endif /* Symbols referring to said sections. */ #ifdef OBJ_ECOFF @@ -311,10 +334,10 @@ static symbolS *alpha_lita_symbol; #endif #ifdef OBJ_EVAX static symbolS *alpha_link_symbol; -static symbolS *alpha_ctors_symbol; -static symbolS *alpha_dtors_symbol; #endif +#ifndef OBJ_EVAX static symbolS *alpha_lit8_symbol; +#endif /* Literal for .litX+0x8000 within .lita. */ #ifdef OBJ_ECOFF @@ -339,6 +362,14 @@ static int alpha_addr32_on = 0; and the section happens to not be on an eight byte boundary, it will align both the symbol and the .quad to an eight byte boundary. */ static symbolS *alpha_insn_label; +#if defined(OBJ_ELF) || defined (OBJ_EVAX) +static symbolS *alpha_prologue_label; +#endif + +#ifdef OBJ_EVAX +/* Symbol associate with the current jsr instruction. */ +static symbolS *alpha_linkage_symbol; +#endif /* Whether we should automatically align data generation pseudo-ops. .align 0 will turn this off. */ @@ -358,6 +389,11 @@ static int alpha_debug; int alpha_flag_mdebug = -1; #endif +#ifdef OBJ_EVAX +/* Whether to perform the VMS procedure call optimization. */ +int alpha_flag_replace = 1; +#endif + /* Don't fully resolve relocations, allowing code movement in the linker. */ static int alpha_flag_relax; @@ -366,7 +402,7 @@ static int g_switch_value = 8; #ifdef OBJ_EVAX /* Collect information about current procedure here. */ -static struct +struct alpha_evax_procs { symbolS *symbol; /* Proc pdesc symbol. */ int pdsckind; @@ -379,7 +415,17 @@ static struct long fmask; int type; int prologue; -} alpha_evax_proc; + symbolS *handler; + int handler_data; +}; + +/* Linked list of .linkage fixups. */ +struct alpha_linkage_fixups *alpha_linkage_fixup_root; +static struct alpha_linkage_fixups *alpha_linkage_fixup_tail; + +/* Current procedure descriptor. */ +static struct alpha_evax_procs *alpha_evax_proc; +static struct alpha_evax_procs alpha_evax_proc_data; static int alpha_flag_hash_long_names = 0; /* -+ */ static int alpha_flag_show_after_trunc = 0; /* -H */ @@ -407,7 +453,7 @@ static const struct alpha_reloc_op_tag const char *name; /* String to lookup. */ size_t length; /* Size of the string. */ operatorT op; /* Which operator to use. */ - bfd_reloc_code_real_type reloc; /* Relocation before frob. */ + extended_bfd_reloc_code_real_type reloc; unsigned int require_seq : 1; /* Require a sequence number. */ unsigned int allow_seq : 1; /* Allow a sequence number. */ } @@ -451,6 +497,10 @@ static const int alpha_num_reloc_op struct alpha_reloc_tag { fixS *master; /* The literal reloc. */ +#ifdef OBJ_EVAX + struct symbol *sym; /* Linkage section item symbol. */ + struct symbol *psym; /* Pdesc symbol. */ +#endif fixS *slaves; /* Head of linked list of lituses. */ segT segment; /* Segment relocs are in or undefined_section. */ long sequence; /* Sequence #. */ @@ -524,9 +574,13 @@ static const char * const mskXh_op[] = { NULL, "mskwh", "msklh", "mskqh" }; static const char * const stX_op[] = { "stb", "stw", "stl", "stq" }; static const char * const ldXu_op[] = { "ldbu", "ldwu", NULL, NULL }; -static void assemble_insn (const struct alpha_opcode *, const expressionS *, int, struct alpha_insn *, bfd_reloc_code_real_type); +static void assemble_insn (const struct alpha_opcode *, const expressionS *, int, struct alpha_insn *, extended_bfd_reloc_code_real_type); static void emit_insn (struct alpha_insn *); static void assemble_tokens (const char *, const expressionS *, int, int); +#ifdef OBJ_EVAX +static const char *s_alpha_section_name (void); +static symbolS *add_to_link_pool (symbolS *, offsetT); +#endif static struct alpha_reloc_tag * get_alpha_reloc_tag (long sequence) @@ -542,19 +596,26 @@ get_alpha_reloc_tag (long sequence) size_t len = strlen (buffer); const char *errmsg; - info = xcalloc (sizeof (struct alpha_reloc_tag) + len, 1); + info = (struct alpha_reloc_tag *) + xcalloc (sizeof (struct alpha_reloc_tag) + len, 1); info->segment = now_seg; info->sequence = sequence; strcpy (info->string, buffer); errmsg = hash_insert (alpha_literal_hash, info->string, (void *) info); if (errmsg) - as_fatal (errmsg); + as_fatal ("%s", errmsg); +#ifdef OBJ_EVAX + info->sym = 0; + info->psym = 0; +#endif } return info; } +#ifndef OBJ_EVAX + static void alpha_adjust_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, @@ -718,6 +779,8 @@ alpha_before_fix (void) if (alpha_literal_hash) bfd_map_over_sections (stdoutput, alpha_adjust_relocs, NULL); } + +#endif #ifdef DEBUG_ALPHA static void @@ -858,8 +921,7 @@ tokenize_arguments (char *str, ++input_line_pointer; SKIP_WHITESPACE (); - p = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (&p); /* Parse !relocation_type. */ len = input_line_pointer - p; @@ -880,7 +942,7 @@ tokenize_arguments (char *str, } *input_line_pointer = c; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); if (*input_line_pointer != '!') { if (r->require_seq) @@ -943,6 +1005,7 @@ tokenize_arguments (char *str, /* ... then fall through to plain expression. */ input_line_pointer = hold; } + /* Fall through. */ default: if (saw_arg && !saw_comma) @@ -1176,7 +1239,8 @@ static long load_expression (int targreg, const expressionS *exp, int *pbasereg, - expressionS *poffset) + expressionS *poffset, + const char *opname) { long emit_lituse = 0; offsetT addend = exp->X_add_number; @@ -1227,7 +1291,7 @@ load_expression (int targreg, assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - assert (insn.nfixups == 1); + gas_assert (insn.nfixups == 1); insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL; insn.sequence = emit_lituse = next_sequence_num--; #endif /* OBJ_ECOFF */ @@ -1263,49 +1327,130 @@ load_expression (int targreg, assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - assert (insn.nfixups == 1); + gas_assert (insn.nfixups == 1); insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL; insn.sequence = emit_lituse = next_sequence_num--; #endif /* OBJ_ELF */ #ifdef OBJ_EVAX - offsetT link; - /* Find symbol or symbol pointer in link section. */ - if (exp->X_add_symbol == alpha_evax_proc.symbol) + if (exp->X_add_symbol == alpha_evax_proc->symbol) { + /* Linkage-relative expression. */ + set_tok_reg (newtok[0], targreg); + if (range_signed_16 (addend)) { - set_tok_reg (newtok[0], targreg); set_tok_const (newtok[1], addend); - set_tok_preg (newtok[2], basereg); - assemble_tokens_to_insn ("lda", newtok, 3, &insn); addend = 0; } else { - set_tok_reg (newtok[0], targreg); set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], basereg); - assemble_tokens_to_insn ("lda", newtok, 3, &insn); } + set_tok_preg (newtok[2], basereg); + assemble_tokens_to_insn ("lda", newtok, 3, &insn); } else { - if (!range_signed_32 (addend)) + const char *symname = S_GET_NAME (exp->X_add_symbol); + const char *ptr1, *ptr2; + int symlen = strlen (symname); + + if ((symlen > 4 && + strcmp (ptr2 = &symname [symlen - 4], "..lk") == 0)) { - link = add_to_link_pool (alpha_evax_proc.symbol, - exp->X_add_symbol, addend); - addend = 0; + /* Access to an item whose address is stored in the linkage + section. Just read the address. */ + set_tok_reg (newtok[0], targreg); + + newtok[1] = *exp; + newtok[1].X_op = O_subtract; + newtok[1].X_op_symbol = alpha_evax_proc->symbol; + + set_tok_preg (newtok[2], basereg); + assemble_tokens_to_insn ("ldq", newtok, 3, &insn); + alpha_linkage_symbol = exp->X_add_symbol; + + if (poffset) + set_tok_const (*poffset, 0); + + if (alpha_flag_replace && targreg == 26) + { + /* Add a NOP fixup for 'ldX $26,YYY..NAME..lk'. */ + char *ensymname; + symbolS *ensym; + + /* Build the entry name as 'NAME..en'. */ + ptr1 = strstr (symname, "..") + 2; + if (ptr1 > ptr2) + ptr1 = symname; + ensymname = XNEWVEC (char, ptr2 - ptr1 + 5); + memcpy (ensymname, ptr1, ptr2 - ptr1); + memcpy (ensymname + (ptr2 - ptr1), "..en", 5); + + gas_assert (insn.nfixups + 1 <= MAX_INSN_FIXUPS); + insn.fixups[insn.nfixups].reloc = BFD_RELOC_ALPHA_NOP; + ensym = symbol_find_or_make (ensymname); + free (ensymname); + symbol_mark_used (ensym); + /* The fixup must be the same as the BFD_RELOC_ALPHA_BOH + case in emit_jsrjmp. See B.4.5.2 of the OpenVMS Linker + Utility Manual. */ + insn.fixups[insn.nfixups].exp.X_op = O_symbol; + insn.fixups[insn.nfixups].exp.X_add_symbol = ensym; + insn.fixups[insn.nfixups].exp.X_add_number = 0; + insn.fixups[insn.nfixups].xtrasym = alpha_linkage_symbol; + insn.fixups[insn.nfixups].procsym = alpha_evax_proc->symbol; + insn.nfixups++; + + /* ??? Force bsym to be instantiated now, as it will be + too late to do so in tc_gen_reloc. */ + symbol_get_bfdsym (exp->X_add_symbol); + } + else if (alpha_flag_replace && targreg == 27) + { + /* Add a lda fixup for 'ldX $27,YYY.NAME..lk+8'. */ + char *psymname; + symbolS *psym; + + /* Extract NAME. */ + ptr1 = strstr (symname, "..") + 2; + if (ptr1 > ptr2) + ptr1 = symname; + psymname = xmemdup0 (ptr1, ptr2 - ptr1); + + gas_assert (insn.nfixups + 1 <= MAX_INSN_FIXUPS); + insn.fixups[insn.nfixups].reloc = BFD_RELOC_ALPHA_LDA; + psym = symbol_find_or_make (psymname); + free (psymname); + symbol_mark_used (psym); + insn.fixups[insn.nfixups].exp.X_op = O_subtract; + insn.fixups[insn.nfixups].exp.X_add_symbol = psym; + insn.fixups[insn.nfixups].exp.X_op_symbol = alpha_evax_proc->symbol; + insn.fixups[insn.nfixups].exp.X_add_number = 0; + insn.fixups[insn.nfixups].xtrasym = alpha_linkage_symbol; + insn.fixups[insn.nfixups].procsym = alpha_evax_proc->symbol; + insn.nfixups++; + } + + emit_insn (&insn); + return 0; } else - link = add_to_link_pool (alpha_evax_proc.symbol, - exp->X_add_symbol, 0); + { + /* Not in the linkage section. Put the value into the linkage + section. */ + symbolS *linkexp; - set_tok_reg (newtok[0], targreg); - set_tok_const (newtok[1], link); - set_tok_preg (newtok[2], basereg); - assemble_tokens_to_insn ("ldq", newtok, 3, &insn); + if (!range_signed_32 (addend)) + addend = sign_extend_32 (addend); + linkexp = add_to_link_pool (exp->X_add_symbol, 0); + set_tok_reg (newtok[0], targreg); + set_tok_sym (newtok[1], linkexp, 0); + set_tok_preg (newtok[2], basereg); + assemble_tokens_to_insn ("ldq", newtok, 3, &insn); + } } #endif /* OBJ_EVAX */ @@ -1335,7 +1480,7 @@ load_expression (int targreg, set_tok_reg (newtok[0], targreg); newtok[1] = *exp; set_tok_preg (newtok[2], basereg); - assemble_tokens ("lda", newtok, 3, 0); + assemble_tokens (opname, newtok, 3, 0); if (poffset) set_tok_const (*poffset, 0); @@ -1357,16 +1502,19 @@ load_expression (int targreg, if (!range_signed_32 (addend)) { +#ifdef OBJ_EVAX + symbolS *litexp; +#else offsetT lit; long seq_num = next_sequence_num--; +#endif /* For 64-bit addends, just put it in the literal pool. */ #ifdef OBJ_EVAX /* Emit "ldq targreg, lit(basereg)". */ - lit = add_to_link_pool (alpha_evax_proc.symbol, - section_symbol (absolute_section), addend); + litexp = add_to_link_pool (section_symbol (absolute_section), addend); set_tok_reg (newtok[0], targreg); - set_tok_const (newtok[1], lit); + set_tok_sym (newtok[1], litexp, 0); set_tok_preg (newtok[2], alpha_gp_register); assemble_tokens ("ldq", newtok, 3, 0); #else @@ -1412,7 +1560,7 @@ load_expression (int targreg, assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - assert (insn.nfixups == 1); + gas_assert (insn.nfixups == 1); #ifdef OBJ_ECOFF insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL; #endif @@ -1430,7 +1578,7 @@ load_expression (int targreg, assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - assert (insn.nfixups < MAX_INSN_FIXUPS); + gas_assert (insn.nfixups < MAX_INSN_FIXUPS); insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE; insn.fixups[insn.nfixups].exp.X_op = O_absent; insn.nfixups++; @@ -1525,7 +1673,7 @@ emit_lda (const expressionS *tok, else basereg = tok[2].X_add_number; - (void) load_expression (tok[0].X_add_number, &tok[1], &basereg, NULL); + (void) load_expression (tok[0].X_add_number, &tok[1], &basereg, NULL, "lda"); } /* The ldah macro differs from the ldah instruction in that it has $31 @@ -1631,18 +1779,31 @@ emit_insn (struct alpha_insn *insn) } else { - reloc_howto_type *reloc_howto - = bfd_reloc_type_lookup (stdoutput, fixup->reloc); - assert (reloc_howto); + reloc_howto_type *reloc_howto = + bfd_reloc_type_lookup (stdoutput, + (bfd_reloc_code_real_type) fixup->reloc); + gas_assert (reloc_howto); size = bfd_get_reloc_size (reloc_howto); - assert (size >= 1 && size <= 4); + + switch (fixup->reloc) + { +#ifdef OBJ_EVAX + case BFD_RELOC_ALPHA_NOP: + case BFD_RELOC_ALPHA_BSR: + case BFD_RELOC_ALPHA_LDA: + case BFD_RELOC_ALPHA_BOH: + break; +#endif + default: + gas_assert (size >= 1 && size <= 4); + } pcrel = reloc_howto->pc_relative; } fixP = fix_new_exp (frag_now, f - frag_now->fr_literal, size, - &fixup->exp, pcrel, fixup->reloc); + &fixup->exp, pcrel, (bfd_reloc_code_real_type) fixup->reloc); /* Turn off complaints that the addend is too large for some fixups, and copy in the sequence number for the explicit relocations. */ @@ -1784,6 +1945,18 @@ emit_insn (struct alpha_insn *insn) fixP->tc_fix_data.info = info; break; #endif +#ifdef OBJ_EVAX + case BFD_RELOC_ALPHA_NOP: + case BFD_RELOC_ALPHA_LDA: + case BFD_RELOC_ALPHA_BSR: + case BFD_RELOC_ALPHA_BOH: + info = get_alpha_reloc_tag (next_sequence_num--); + fixP->tc_fix_data.info = info; + fixP->tc_fix_data.info->sym = fixup->xtrasym; + fixP->tc_fix_data.info->psym = fixup->procsym; + break; +#endif + default: if ((int) fixup->reloc < 0) { @@ -1801,7 +1974,7 @@ static unsigned insert_operand (unsigned insn, const struct alpha_operand *operand, offsetT val, - char *file, + const char *file, unsigned line) { if (operand->bits != 32 && !(operand->flags & AXP_OPERAND_NOOVERFLOW)) @@ -1820,7 +1993,7 @@ insert_operand (unsigned insn, } if (val < min || val > max) - as_warn_value_out_of_range (_("operand"), val, min, max, file, line); + as_bad_value_out_of_range (_("operand"), val, min, max, file, line); } if (operand->insert) @@ -1829,7 +2002,7 @@ insert_operand (unsigned insn, insn = (*operand->insert) (insn, val, &errmsg); if (errmsg) - as_warn (errmsg); + as_warn ("%s", errmsg); } else insn |= ((val & ((1 << operand->bits) - 1)) << operand->shift); @@ -1845,7 +2018,7 @@ assemble_insn (const struct alpha_opcode *opcode, const expressionS *tok, int ntok, struct alpha_insn *insn, - bfd_reloc_code_real_type reloc) + extended_bfd_reloc_code_real_type reloc) { const struct alpha_operand *reloc_operand = NULL; const expressionS *reloc_exp = NULL; @@ -1904,7 +2077,7 @@ assemble_insn (const struct alpha_opcode *opcode, case O_constant: image = insert_operand (image, operand, t->X_add_number, NULL, 0); - assert (reloc_operand == NULL); + gas_assert (reloc_operand == NULL); reloc_operand = operand; reloc_exp = t; break; @@ -1934,7 +2107,7 @@ assemble_insn (const struct alpha_opcode *opcode, if (reloc == BFD_RELOC_UNUSED) reloc = operand->default_reloc; - assert (reloc_operand == NULL); + gas_assert (reloc_operand == NULL); reloc_operand = operand; reloc_exp = t; } @@ -1963,11 +2136,13 @@ assemble_insn (const struct alpha_opcode *opcode, } /* 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) + the relocation width should match the operand width. + Take care of -MDISP in operand table. */ + else if (reloc < BFD_RELOC_UNUSED && reloc > 0) { reloc_howto_type *reloc_howto - = bfd_reloc_type_lookup (stdoutput, reloc); + = bfd_reloc_type_lookup (stdoutput, + (bfd_reloc_code_real_type) reloc); if (reloc_operand == NULL || reloc_howto->bitsize != reloc_operand->bits) { @@ -2000,14 +2175,21 @@ emit_ir_load (const expressionS *tok, long lituse; expressionS newtok[3]; struct alpha_insn insn; + const char *symname + = tok[1].X_add_symbol ? S_GET_NAME (tok[1].X_add_symbol): ""; + int symlen = strlen (symname); if (ntok == 2) basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register); else basereg = tok[2].X_add_number; - lituse = load_expression (tok[0].X_add_number, &tok[1], &basereg, - &newtok[1]); + lituse = load_expression (tok[0].X_add_number, &tok[1], + &basereg, &newtok[1], (const char *) opname); + + if (basereg == alpha_gp_register && + (symlen > 4 && strcmp (&symname [symlen - 4], "..lk") == 0)) + return; newtok[0] = tok[0]; set_tok_preg (newtok[2], basereg); @@ -2016,7 +2198,7 @@ emit_ir_load (const expressionS *tok, if (lituse) { - assert (insn.nfixups < MAX_INSN_FIXUPS); + gas_assert (insn.nfixups < MAX_INSN_FIXUPS); insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE; insn.fixups[insn.nfixups].exp.X_op = O_absent; insn.nfixups++; @@ -2049,7 +2231,8 @@ emit_loadstore (const expressionS *tok, 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]); + lituse = load_expression (AXP_REG_AT, &tok[1], + &basereg, &newtok[1], (const char *) opname); } else { @@ -2064,7 +2247,7 @@ emit_loadstore (const expressionS *tok, if (lituse) { - assert (insn.nfixups < MAX_INSN_FIXUPS); + gas_assert (insn.nfixups < MAX_INSN_FIXUPS); insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE; insn.fixups[insn.nfixups].exp.X_op = O_absent; insn.nfixups++; @@ -2100,7 +2283,7 @@ emit_ldXu (const expressionS *tok, basereg = tok[2].X_add_number; /* Emit "lda $at, exp". */ - lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL); + lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL, "lda"); /* Emit "ldq_u targ, 0($at)". */ newtok[0] = tok[0]; @@ -2110,7 +2293,7 @@ emit_ldXu (const expressionS *tok, if (lituse) { - assert (insn.nfixups < MAX_INSN_FIXUPS); + gas_assert (insn.nfixups < MAX_INSN_FIXUPS); insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE; insn.fixups[insn.nfixups].exp.X_op = O_absent; insn.nfixups++; @@ -2126,7 +2309,7 @@ emit_ldXu (const expressionS *tok, if (lituse) { - assert (insn.nfixups < MAX_INSN_FIXUPS); + gas_assert (insn.nfixups < MAX_INSN_FIXUPS); insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BYTOFF; insn.fixups[insn.nfixups].exp.X_op = O_absent; insn.nfixups++; @@ -2252,7 +2435,7 @@ emit_stX (const expressionS *tok, basereg = tok[2].X_add_number; /* Emit "lda $at, exp". */ - lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL); + lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL, "lda"); /* Emit "ldq_u $t9, 0($at)". */ set_tok_reg (newtok[0], AXP_REG_T9); @@ -2262,7 +2445,7 @@ emit_stX (const expressionS *tok, if (lituse) { - assert (insn.nfixups < MAX_INSN_FIXUPS); + gas_assert (insn.nfixups < MAX_INSN_FIXUPS); insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE; insn.fixups[insn.nfixups].exp.X_op = O_absent; insn.nfixups++; @@ -2279,7 +2462,7 @@ emit_stX (const expressionS *tok, if (lituse) { - assert (insn.nfixups < MAX_INSN_FIXUPS); + gas_assert (insn.nfixups < MAX_INSN_FIXUPS); insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BYTOFF; insn.fixups[insn.nfixups].exp.X_op = O_absent; insn.nfixups++; @@ -2295,7 +2478,7 @@ emit_stX (const expressionS *tok, if (lituse) { - assert (insn.nfixups < MAX_INSN_FIXUPS); + gas_assert (insn.nfixups < MAX_INSN_FIXUPS); insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BYTOFF; insn.fixups[insn.nfixups].exp.X_op = O_absent; insn.nfixups++; @@ -2315,7 +2498,7 @@ emit_stX (const expressionS *tok, if (lituse) { - assert (insn.nfixups < MAX_INSN_FIXUPS); + gas_assert (insn.nfixups < MAX_INSN_FIXUPS); insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE; insn.fixups[insn.nfixups].exp.X_op = O_absent; insn.nfixups++; @@ -2662,15 +2845,14 @@ emit_jsrjmp (const expressionS *tok, else { int basereg = alpha_gp_register; - lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], &basereg, NULL); + lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], + &basereg, NULL, opname); } #endif set_tok_cpreg (newtok[1], r); -#ifdef OBJ_EVAX - /* FIXME: Add hint relocs to BFD for evax. */ -#else +#ifndef OBJ_EVAX if (tokidx < ntok) newtok[2] = tok[tokidx]; else @@ -2681,13 +2863,51 @@ emit_jsrjmp (const expressionS *tok, if (lituse) { - assert (insn.nfixups < MAX_INSN_FIXUPS); + gas_assert (insn.nfixups < MAX_INSN_FIXUPS); insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_JSR; insn.fixups[insn.nfixups].exp.X_op = O_absent; insn.nfixups++; insn.sequence = lituse; } +#ifdef OBJ_EVAX + if (alpha_flag_replace + && r == AXP_REG_RA + && tok[tokidx].X_add_symbol + && alpha_linkage_symbol) + { + /* Create a BOH reloc for 'jsr $27,NAME'. */ + const char *symname = S_GET_NAME (tok[tokidx].X_add_symbol); + int symlen = strlen (symname); + char *ensymname; + + /* Build the entry name as 'NAME..en'. */ + ensymname = XNEWVEC (char, symlen + 5); + memcpy (ensymname, symname, symlen); + memcpy (ensymname + symlen, "..en", 5); + + gas_assert (insn.nfixups < MAX_INSN_FIXUPS); + if (insn.nfixups > 0) + { + memmove (&insn.fixups[1], &insn.fixups[0], + sizeof(struct alpha_fixup) * insn.nfixups); + } + + /* The fixup must be the same as the BFD_RELOC_ALPHA_NOP + case in load_expression. See B.4.5.2 of the OpenVMS + Linker Utility Manual. */ + insn.fixups[0].reloc = BFD_RELOC_ALPHA_BOH; + insn.fixups[0].exp.X_op = O_symbol; + insn.fixups[0].exp.X_add_symbol = symbol_find_or_make (ensymname); + insn.fixups[0].exp.X_add_number = 0; + insn.fixups[0].xtrasym = alpha_linkage_symbol; + insn.fixups[0].procsym = alpha_evax_proc->symbol; + insn.nfixups++; + alpha_linkage_symbol = 0; + free (ensymname); + } +#endif + emit_insn (&insn); } @@ -2729,7 +2949,7 @@ emit_retjcr (const expressionS *tok, /* Implement the ldgp macro. */ static void -emit_ldgp (const expressionS *tok, +emit_ldgp (const expressionS *tok ATTRIBUTE_UNUSED, int ntok ATTRIBUTE_UNUSED, const void * unused ATTRIBUTE_UNUSED) { @@ -3087,7 +3307,7 @@ assemble_tokens (const char *opname, const struct alpha_opcode *opcode; const struct alpha_macro *macro; int cpumatch = 1; - bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED; + extended_bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED; #ifdef RELOC_OP_P /* If a user-specified relocation is present, this is not a macro. */ @@ -3148,25 +3368,24 @@ assemble_tokens (const char *opname, #ifdef OBJ_EVAX -/* Add symbol+addend to link pool. - Return offset from basesym to entry in link pool. +/* Add sym+addend to link pool. + Return offset from curent procedure value (pv) to entry in link pool. Add new fixup only if offset isn't 16bit. */ -valueT -add_to_link_pool (symbolS *basesym, - symbolS *sym, - offsetT addend) +static symbolS * +add_to_link_pool (symbolS *sym, offsetT addend) { + symbolS *basesym; segT current_section = now_seg; int current_subsec = now_subseg; - valueT offset; - bfd_reloc_code_real_type reloc_type; char *p; segment_info_type *seginfo = seg_info (alpha_link_section); fixS *fixp; + symbolS *linksym, *expsym; + expressionS e; - offset = - *symbol_get_obj (basesym); + basesym = alpha_evax_proc->symbol; /* @@ This assumes all entries in a given section will be of the same size... Probably correct, but unwise to rely on. */ @@ -3175,31 +3394,41 @@ add_to_link_pool (symbolS *basesym, if (seginfo->frchainP) for (fixp = seginfo->frchainP->fix_root; fixp != (fixS *) NULL; - fixp = fixp->fx_next, offset += 8) + fixp = fixp->fx_next) { - if (fixp->fx_addsy == sym && fixp->fx_offset == addend) - { - if (range_signed_16 (offset)) - { - return offset; - } - } + if (fixp->fx_addsy == sym + && fixp->fx_offset == (valueT)addend + && fixp->tc_fix_data.info + && fixp->tc_fix_data.info->sym + && fixp->tc_fix_data.info->sym->sy_value.X_op_symbol == basesym) + return fixp->tc_fix_data.info->sym; } - /* Not found in 16bit signed range. */ - + /* Not found, add a new entry. */ subseg_set (alpha_link_section, 0); + linksym = symbol_new + (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now); p = frag_more (8); memset (p, 0, 8); - fix_new (frag_now, p - frag_now->fr_literal, 8, sym, addend, 0, - BFD_RELOC_64); + /* Create a symbol for 'basesym - linksym' (offset of the added entry). */ + e.X_op = O_subtract; + e.X_add_symbol = linksym; + e.X_op_symbol = basesym; + e.X_add_number = 0; + expsym = make_expr_symbol (&e); + + /* Create a fixup for the entry. */ + fixp = fix_new + (frag_now, p - frag_now->fr_literal, 8, sym, addend, 0, BFD_RELOC_64); + fixp->tc_fix_data.info = get_alpha_reloc_tag (next_sequence_num--); + fixp->tc_fix_data.info->sym = expsym; subseg_set (current_section, current_subsec); - seginfo->literal_pool_size += 8; - return offset; -} + /* Return the symbol. */ + return expsym; +} #endif /* OBJ_EVAX */ /* Assembler directives. */ @@ -3209,12 +3438,24 @@ add_to_link_pool (symbolS *basesym, static void s_alpha_text (int i) - { #ifdef OBJ_ELF obj_elf_text (i); #else s_text (i); +#endif +#ifdef OBJ_EVAX + { + symbolS * symbolP; + + symbolP = symbol_find (".text"); + if (symbolP == NULL) + { + symbolP = symbol_make (".text"); + S_SET_SEGMENT (symbolP, text_section); + symbol_table_insert (symbolP); + } + } #endif alpha_insn_label = NULL; alpha_auto_align_on = 1; @@ -3239,8 +3480,7 @@ s_alpha_data (int i) #if defined (OBJ_ECOFF) || defined (OBJ_EVAX) -/* Handle the OSF/1 and openVMS .comm pseudo quirks. - openVMS constructs a section for every common symbol. */ +/* Handle the OSF/1 and openVMS .comm pseudo quirks. */ static void s_alpha_comm (int ignore ATTRIBUTE_UNUSED) @@ -3248,22 +3488,20 @@ s_alpha_comm (int ignore ATTRIBUTE_UNUSED) char *name; char c; char *p; - offsetT temp; + offsetT size; symbolS *symbolP; #ifdef OBJ_EVAX - segT current_section = now_seg; - int current_subsec = now_subseg; - segT new_seg; + offsetT temp; + int log_align = 0; #endif - name = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (&name); /* Just after name is now '\0'. */ p = input_line_pointer; *p = c; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); /* Alpha OSF/1 compiler doesn't provide the comma, gcc does. */ if (*input_line_pointer == ',') @@ -3271,35 +3509,17 @@ s_alpha_comm (int ignore ATTRIBUTE_UNUSED) input_line_pointer++; SKIP_WHITESPACE (); } - if ((temp = get_absolute_expression ()) < 0) + if ((size = get_absolute_expression ()) < 0) { - as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) temp); + as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) size); ignore_rest_of_line (); return; } *p = 0; symbolP = symbol_find_or_make (name); - -#ifdef OBJ_EVAX - /* Make a section for the common symbol. */ - new_seg = subseg_new (xstrdup (name), 0); -#endif - *p = c; -#ifdef OBJ_EVAX - /* Alignment might follow. */ - if (*input_line_pointer == ',') - { - offsetT align; - - input_line_pointer++; - align = get_absolute_expression (); - bfd_set_section_alignment (stdoutput, new_seg, align); - } -#endif - if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) { as_bad (_("Ignoring attempt to re-define symbol")); @@ -3308,44 +3528,108 @@ s_alpha_comm (int ignore ATTRIBUTE_UNUSED) } #ifdef OBJ_EVAX - if (bfd_section_size (stdoutput, new_seg) > 0) + if (*input_line_pointer != ',') + temp = 8; /* Default alignment. */ + else + { + input_line_pointer++; + SKIP_WHITESPACE (); + temp = get_absolute_expression (); + } + + /* ??? Unlike on OSF/1, the alignment factor is not in log units. */ + while ((temp >>= 1) != 0) + ++log_align; + + if (*input_line_pointer == ',') { - if (bfd_section_size (stdoutput, new_seg) != temp) - as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."), - S_GET_NAME (symbolP), - (long) bfd_section_size (stdoutput, new_seg), - (long) temp); + /* Extended form of the directive + + .comm symbol, size, alignment, section + + where the "common" semantics is transferred to the section. + The symbol is effectively an alias for the section name. */ + + segT sec; + const char *sec_name; + symbolS *sec_symbol; + segT current_seg = now_seg; + subsegT current_subseg = now_subseg; + int cur_size; + + input_line_pointer++; + SKIP_WHITESPACE (); + sec_name = s_alpha_section_name (); + sec_symbol = symbol_find_or_make (sec_name); + sec = subseg_new (sec_name, 0); + S_SET_SEGMENT (sec_symbol, sec); + symbol_get_bfdsym (sec_symbol)->flags |= BSF_SECTION_SYM; + bfd_vms_set_section_flags (stdoutput, sec, 0, + EGPS__V_OVR | EGPS__V_GBL | EGPS__V_NOMOD); + record_alignment (sec, log_align); + + /* Reuse stab_string_size to store the size of the section. */ + cur_size = seg_info (sec)->stabu.stab_string_size; + if ((int) size > cur_size) + { + char *pfrag + = frag_var (rs_fill, 1, 1, (relax_substateT)0, NULL, + (valueT)size - (valueT)cur_size, NULL); + *pfrag = 0; + seg_info (sec)->stabu.stab_string_size = (int)size; + } + + S_SET_SEGMENT (symbolP, sec); + + subseg_set (current_seg, current_subseg); } -#else - if (S_GET_VALUE (symbolP)) + else { - if (S_GET_VALUE (symbolP) != (valueT) temp) - as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."), - S_GET_NAME (symbolP), - (long) S_GET_VALUE (symbolP), - (long) temp); + /* Regular form of the directive + + .comm symbol, size, alignment + + where the "common" semantics in on the symbol. + These symbols are assembled in the .bss section. */ + + char *pfrag; + segT current_seg = now_seg; + subsegT current_subseg = now_subseg; + + subseg_set (bss_section, 1); + frag_align (log_align, 0, 0); + record_alignment (bss_section, log_align); + + symbol_set_frag (symbolP, frag_now); + pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP, + size, NULL); + *pfrag = 0; + + S_SET_SEGMENT (symbolP, bss_section); + + subseg_set (current_seg, current_subseg); } #endif + + if (S_GET_VALUE (symbolP)) + { + if (S_GET_VALUE (symbolP) != (valueT) size) + as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."), + S_GET_NAME (symbolP), + (long) S_GET_VALUE (symbolP), + (long) size); + } else { -#ifdef OBJ_EVAX - subseg_set (new_seg, 0); - p = frag_more (temp); - new_seg->flags |= SEC_IS_COMMON; - S_SET_SEGMENT (symbolP, new_seg); -#else - S_SET_VALUE (symbolP, (valueT) temp); - S_SET_SEGMENT (symbolP, bfd_com_section_ptr); +#ifndef OBJ_EVAX + S_SET_VALUE (symbolP, (valueT) size); #endif S_SET_EXTERNAL (symbolP); } -#ifdef OBJ_EVAX - subseg_set (current_section, current_subsec); +#ifndef OBJ_EVAX + know (symbolP->sy_frag == &zero_address_frag); #endif - - know (symbol_get_frag (symbolP) == &zero_address_frag); - demand_empty_rest_of_line (); } @@ -3359,9 +3643,7 @@ s_alpha_comm (int ignore ATTRIBUTE_UNUSED) static void s_alpha_rdata (int ignore ATTRIBUTE_UNUSED) { - int temp; - - temp = get_absolute_expression (); + get_absolute_expression (); subseg_new (".rdata", 0); demand_empty_rest_of_line (); alpha_insn_label = NULL; @@ -3379,9 +3661,7 @@ s_alpha_rdata (int ignore ATTRIBUTE_UNUSED) static void s_alpha_sdata (int ignore ATTRIBUTE_UNUSED) { - int temp; - - temp = get_absolute_expression (); + get_absolute_expression (); subseg_new (".sdata", 0); demand_empty_rest_of_line (); alpha_insn_label = NULL; @@ -3411,6 +3691,8 @@ 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; +extern int all_cfi_sections; + /* Handle the .section pseudo-op. This is like the usual one, but it clears alpha_insn_label and restores auto alignment. */ @@ -3432,13 +3714,15 @@ s_alpha_ent (int dummy ATTRIBUTE_UNUSED) else { char *name, name_end; - name = input_line_pointer; - name_end = get_symbol_end (); + + name_end = get_symbol_name (&name); + /* CFI_EMIT_eh_frame is the default. */ + all_cfi_sections = CFI_EMIT_eh_frame; if (! is_name_beginner (*name)) { as_warn (_(".ent directive has no name")); - *input_line_pointer = name_end; + (void) restore_line_pointer (name_end); } else { @@ -3450,7 +3734,7 @@ s_alpha_ent (int dummy ATTRIBUTE_UNUSED) sym = symbol_find_or_make (name); symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION; - cur_frame_data = calloc (1, sizeof (*cur_frame_data)); + cur_frame_data = XCNEW (struct alpha_elf_frame_data); cur_frame_data->func_sym = sym; /* Provide sensible defaults. */ @@ -3463,7 +3747,7 @@ s_alpha_ent (int dummy ATTRIBUTE_UNUSED) /* The .ent directive is sometimes followed by a number. Not sure what it really means, but ignore it. */ *input_line_pointer = name_end; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); if (*input_line_pointer == ',') { input_line_pointer++; @@ -3484,13 +3768,12 @@ s_alpha_end (int dummy ATTRIBUTE_UNUSED) else { char *name, name_end; - name = input_line_pointer; - name_end = get_symbol_end (); + + name_end = get_symbol_name (&name); if (! is_name_beginner (*name)) { as_warn (_(".end directive has no name")); - *input_line_pointer = name_end; } else { @@ -3506,7 +3789,7 @@ s_alpha_end (int dummy ATTRIBUTE_UNUSED) if (sym && cur_frame_data) { OBJ_SYMFIELD_TYPE *obj = symbol_get_obj (sym); - expressionS *exp = xmalloc (sizeof (expressionS)); + expressionS *exp = XNEW (expressionS); obj->size = exp; exp->X_op = O_subtract; @@ -3518,9 +3801,9 @@ s_alpha_end (int dummy ATTRIBUTE_UNUSED) } cur_frame_data = NULL; - - *input_line_pointer = name_end; } + + (void) restore_line_pointer (name_end); demand_empty_rest_of_line (); } } @@ -3623,6 +3906,8 @@ s_alpha_prologue (int ignore ATTRIBUTE_UNUSED) arg = get_absolute_expression (); demand_empty_rest_of_line (); + alpha_prologue_label = symbol_new + (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now); if (ECOFF_DEBUGGING) sym = ecoff_get_cur_proc_sym (); @@ -3672,9 +3957,7 @@ s_alpha_file (int ignore ATTRIBUTE_UNUSED) discard_rest_of_line (); len = input_line_pointer - start; - first_file_directive = xmalloc (len + 1); - memcpy (first_file_directive, start, len); - first_file_directive[len] = '\0'; + first_file_directive = xmemdup0 (start, len); input_line_pointer = start; } @@ -3734,7 +4017,7 @@ s_alpha_coff_wrapper (int which) ecoff_directive_val, }; - assert (which >= 0 && which < (int) (sizeof (fns)/sizeof (*fns))); + gas_assert (which >= 0 && which < (int) (sizeof (fns)/sizeof (*fns))); if (ECOFF_DEBUGGING) (*fns[which]) (0); @@ -3760,6 +4043,14 @@ alpha_elf_md_end (void) if (bfd_get_section_by_name (stdoutput, ".eh_frame") != NULL) return; + /* ??? In theory we could look for functions for which we have + generated unwind info via CFI directives, and those we have not. + Those we have not could still get their unwind info from here. + For now, do nothing if we've seen any CFI directives. Note that + the above test will not trigger, as we've not emitted data yet. */ + if (all_fde_data != NULL) + return; + /* Generate .eh_frame data for the unwind directives specified. */ for (p = all_frame_data; p ; p = p->next) if (p->prologue_sym) @@ -3770,6 +4061,7 @@ alpha_elf_md_end (void) S_GET_VALUE (p->func_sym), symbol_get_frag (p->func_sym))); + cfi_set_sections (); 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) @@ -3834,19 +4126,20 @@ s_alpha_usepv (int unused ATTRIBUTE_UNUSED) symbolS *sym; int other; - name = input_line_pointer; - name_end = get_symbol_end (); + name_end = get_symbol_name (&name); if (! is_name_beginner (*name)) { as_bad (_(".usepv directive has no name")); - *input_line_pointer = name_end; + (void) restore_line_pointer (name_end); ignore_rest_of_line (); return; } sym = symbol_find_or_make (name); - *input_line_pointer++ = name_end; + name_end = restore_line_pointer (name_end); + if (! is_end_of_line[(unsigned char) name_end]) + input_line_pointer++; if (name_end != ',') { @@ -3856,8 +4149,8 @@ s_alpha_usepv (int unused ATTRIBUTE_UNUSED) } SKIP_WHITESPACE (); - which = input_line_pointer; - which_end = get_symbol_end (); + + which_end = get_symbol_name (&which); if (strcmp (which, "no") == 0) other = STO_ALPHA_NOPV; @@ -3869,7 +4162,7 @@ s_alpha_usepv (int unused ATTRIBUTE_UNUSED) other = 0; } - *input_line_pointer = which_end; + (void) restore_line_pointer (which_end); demand_empty_rest_of_line (); S_SET_OTHER (sym, other | (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD)); @@ -3886,24 +4179,178 @@ alpha_cfi_frame_initial_instructions (void) #ifdef OBJ_EVAX +/* Get name of section. */ +static const char * +s_alpha_section_name (void) +{ + char *name; + + SKIP_WHITESPACE (); + if (*input_line_pointer == '"') + { + int dummy; + + name = demand_copy_C_string (&dummy); + if (name == NULL) + { + ignore_rest_of_line (); + return NULL; + } + } + else + { + char *end = input_line_pointer; + + while (0 == strchr ("\n\t,; ", *end)) + end++; + if (end == input_line_pointer) + { + as_warn (_("missing name")); + ignore_rest_of_line (); + return NULL; + } + + name = xmemdup0 (input_line_pointer, end - input_line_pointer); + input_line_pointer = end; + } + SKIP_WHITESPACE (); + return name; +} + +/* Put clear/set flags in one flagword. The LSBs are flags to be set, + the MSBs are the flags to be cleared. */ + +#define EGPS__V_NO_SHIFT 16 +#define EGPS__V_MASK 0xffff + +/* Parse one VMS section flag. */ + +static flagword +s_alpha_section_word (char *str, size_t len) +{ + int no = 0; + flagword flag = 0; + + if (len == 5 && strncmp (str, "NO", 2) == 0) + { + no = 1; + str += 2; + len -= 2; + } + + if (len == 3) + { + if (strncmp (str, "PIC", 3) == 0) + flag = EGPS__V_PIC; + else if (strncmp (str, "LIB", 3) == 0) + flag = EGPS__V_LIB; + else if (strncmp (str, "OVR", 3) == 0) + flag = EGPS__V_OVR; + else if (strncmp (str, "REL", 3) == 0) + flag = EGPS__V_REL; + else if (strncmp (str, "GBL", 3) == 0) + flag = EGPS__V_GBL; + else if (strncmp (str, "SHR", 3) == 0) + flag = EGPS__V_SHR; + else if (strncmp (str, "EXE", 3) == 0) + flag = EGPS__V_EXE; + else if (strncmp (str, "WRT", 3) == 0) + flag = EGPS__V_WRT; + else if (strncmp (str, "VEC", 3) == 0) + flag = EGPS__V_VEC; + else if (strncmp (str, "MOD", 3) == 0) + { + flag = no ? EGPS__V_NOMOD : EGPS__V_NOMOD << EGPS__V_NO_SHIFT; + no = 0; + } + else if (strncmp (str, "COM", 3) == 0) + flag = EGPS__V_COM; + } + + if (flag == 0) + { + char c = str[len]; + str[len] = 0; + as_warn (_("unknown section attribute %s"), str); + str[len] = c; + return 0; + } + + if (no) + return flag << EGPS__V_NO_SHIFT; + else + return flag; +} + /* Handle the section specific pseudo-op. */ +#define EVAX_SECTION_COUNT 5 + +static const char *section_name[EVAX_SECTION_COUNT + 1] = + { "NULL", ".rdata", ".comm", ".link", ".ctors", ".dtors" }; + static void s_alpha_section (int secid) { - int temp; -#define EVAX_SECTION_COUNT 5 - static char *section_name[EVAX_SECTION_COUNT + 1] = - { "NULL", ".rdata", ".comm", ".link", ".ctors", ".dtors" }; + const char *name; + char *beg; + segT sec; + flagword vms_flags = 0; + symbolS *symbol; - if ((secid <= 0) || (secid > EVAX_SECTION_COUNT)) + if (secid == 0) { - as_fatal (_("Unknown section directive")); - demand_empty_rest_of_line (); - return; + name = s_alpha_section_name (); + if (name == NULL) + return; + sec = subseg_new (name, 0); + if (*input_line_pointer == ',') + { + /* Skip the comma. */ + ++input_line_pointer; + SKIP_WHITESPACE (); + + do + { + char c; + + SKIP_WHITESPACE (); + c = get_symbol_name (&beg); + *input_line_pointer = c; + + vms_flags |= s_alpha_section_word (beg, input_line_pointer - beg); + + SKIP_WHITESPACE_AFTER_NAME (); + } + while (*input_line_pointer++ == ','); + + --input_line_pointer; + } + + symbol = symbol_find_or_make (name); + S_SET_SEGMENT (symbol, sec); + symbol_get_bfdsym (symbol)->flags |= BSF_SECTION_SYM; + bfd_vms_set_section_flags + (stdoutput, sec, + (vms_flags >> EGPS__V_NO_SHIFT) & EGPS__V_MASK, + vms_flags & EGPS__V_MASK); + } + else + { + get_absolute_expression (); + subseg_new (section_name[secid], 0); } - temp = get_absolute_expression (); - subseg_new (section_name[secid], 0); + + demand_empty_rest_of_line (); + alpha_insn_label = NULL; + alpha_auto_align_on = 1; + alpha_current_align = 0; +} + +static void +s_alpha_literals (int ignore ATTRIBUTE_UNUSED) +{ + subseg_new (".literals", 0); demand_empty_rest_of_line (); alpha_insn_label = NULL; alpha_auto_align_on = 1; @@ -3918,16 +4365,23 @@ s_alpha_ent (int ignore ATTRIBUTE_UNUSED) symbolS *symbol; expressionS symexpr; - alpha_evax_proc.pdsckind = 0; - alpha_evax_proc.framereg = -1; - alpha_evax_proc.framesize = 0; - alpha_evax_proc.rsa_offset = 0; - alpha_evax_proc.ra_save = AXP_REG_RA; - alpha_evax_proc.fp_save = -1; - alpha_evax_proc.imask = 0; - alpha_evax_proc.fmask = 0; - alpha_evax_proc.prologue = 0; - alpha_evax_proc.type = 0; + if (alpha_evax_proc != NULL) + as_bad (_("previous .ent not closed by a .end")); + + alpha_evax_proc = &alpha_evax_proc_data; + + alpha_evax_proc->pdsckind = 0; + alpha_evax_proc->framereg = -1; + alpha_evax_proc->framesize = 0; + alpha_evax_proc->rsa_offset = 0; + alpha_evax_proc->ra_save = AXP_REG_RA; + alpha_evax_proc->fp_save = -1; + alpha_evax_proc->imask = 0; + alpha_evax_proc->fmask = 0; + alpha_evax_proc->prologue = 0; + alpha_evax_proc->type = 0; + alpha_evax_proc->handler = 0; + alpha_evax_proc->handler_data = 0; expression (&symexpr); @@ -3940,7 +4394,37 @@ s_alpha_ent (int ignore ATTRIBUTE_UNUSED) symbol = make_expr_symbol (&symexpr); symbol_get_bfdsym (symbol)->flags |= BSF_FUNCTION; - alpha_evax_proc.symbol = symbol; + alpha_evax_proc->symbol = symbol; + + demand_empty_rest_of_line (); +} + +static void +s_alpha_handler (int is_data) +{ + if (is_data) + alpha_evax_proc->handler_data = get_absolute_expression (); + else + { + char *name, name_end; + + name_end = get_symbol_name (&name); + + if (! is_name_beginner (*name)) + { + as_warn (_(".handler directive has no name")); + } + else + { + symbolS *sym; + + sym = symbol_find_or_make (name); + symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION; + alpha_evax_proc->handler = sym; + } + + (void) restore_line_pointer (name_end); + } demand_empty_rest_of_line (); } @@ -3951,8 +4435,9 @@ static void s_alpha_frame (int ignore ATTRIBUTE_UNUSED) { long val; + int ra; - alpha_evax_proc.framereg = tc_get_register (1); + alpha_evax_proc->framereg = tc_get_register (1); SKIP_WHITESPACE (); if (*input_line_pointer++ != ',' @@ -3964,9 +4449,12 @@ s_alpha_frame (int ignore ATTRIBUTE_UNUSED) return; } - alpha_evax_proc.framesize = val; + alpha_evax_proc->framesize = val; + + ra = tc_get_register (1); + if (ra != AXP_REG_RA) + as_warn (_("Bad RA (%d) register for .frame"), ra); - (void) tc_get_register (1); SKIP_WHITESPACE (); if (*input_line_pointer++ != ',') { @@ -3975,51 +4463,77 @@ s_alpha_frame (int ignore ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); return; } - alpha_evax_proc.rsa_offset = get_absolute_expression (); + alpha_evax_proc->rsa_offset = get_absolute_expression (); +} + +/* Parse .prologue. */ + +static void +s_alpha_prologue (int ignore ATTRIBUTE_UNUSED) +{ + demand_empty_rest_of_line (); + alpha_prologue_label = symbol_new + (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now); } +/* Parse .pdesc ,{null|stack|reg} + Insert a procedure descriptor. */ + static void s_alpha_pdesc (int ignore ATTRIBUTE_UNUSED) { char *name; char name_end; - long val; - register char *p; + char *p; expressionS exp; symbolS *entry_sym; + const char *entry_sym_name; + const char *pdesc_sym_name; fixS *fixp; - segment_info_type *seginfo = seg_info (alpha_link_section); + size_t len; if (now_seg != alpha_link_section) { as_bad (_(".pdesc directive not in link (.link) section")); - demand_empty_rest_of_line (); return; } - if ((alpha_evax_proc.symbol == 0) - || (!S_IS_DEFINED (alpha_evax_proc.symbol))) + expression (&exp); + if (exp.X_op != O_symbol) { - as_fatal (_(".pdesc has no matching .ent")); - demand_empty_rest_of_line (); + as_bad (_(".pdesc directive has no entry symbol")); return; } - *symbol_get_obj (alpha_evax_proc.symbol) = - (valueT) seginfo->literal_pool_size; + entry_sym = make_expr_symbol (&exp); + entry_sym_name = S_GET_NAME (entry_sym); - expression (&exp); - if (exp.X_op != O_symbol) + /* Strip "..en". */ + len = strlen (entry_sym_name); + if (len < 4 || strcmp (entry_sym_name + len - 4, "..en") != 0) { - as_warn (_(".pdesc directive has no entry symbol")); - demand_empty_rest_of_line (); + as_bad (_(".pdesc has a bad entry symbol")); return; } + len -= 4; + pdesc_sym_name = S_GET_NAME (alpha_evax_proc->symbol); - entry_sym = make_expr_symbol (&exp); - /* Save bfd symbol of proc desc in function symbol. */ - symbol_get_bfdsym (alpha_evax_proc.symbol)->udata.p - = symbol_get_bfdsym (entry_sym); + if (!alpha_evax_proc + || !S_IS_DEFINED (alpha_evax_proc->symbol) + || strlen (pdesc_sym_name) != len + || memcmp (entry_sym_name, pdesc_sym_name, len) != 0) + { + as_fatal (_(".pdesc doesn't match with last .ent")); + return; + } + + /* Define pdesc symbol. */ + symbol_set_value_now (alpha_evax_proc->symbol); + + /* Save bfd symbol of proc entry in function symbol. */ + ((struct evax_private_udata_struct *) + symbol_get_bfdsym (alpha_evax_proc->symbol)->udata.p)->enbsym + = symbol_get_bfdsym (entry_sym); SKIP_WHITESPACE (); if (*input_line_pointer++ != ',') @@ -4030,26 +4544,26 @@ s_alpha_pdesc (int ignore ATTRIBUTE_UNUSED) } SKIP_WHITESPACE (); - name = input_line_pointer; - name_end = get_symbol_end (); + name_end = get_symbol_name (&name); if (strncmp (name, "stack", 5) == 0) - alpha_evax_proc.pdsckind = PDSC_S_K_KIND_FP_STACK; + alpha_evax_proc->pdsckind = PDSC_S_K_KIND_FP_STACK; else if (strncmp (name, "reg", 3) == 0) - alpha_evax_proc.pdsckind = PDSC_S_K_KIND_FP_REGISTER; + alpha_evax_proc->pdsckind = PDSC_S_K_KIND_FP_REGISTER; else if (strncmp (name, "null", 4) == 0) - alpha_evax_proc.pdsckind = PDSC_S_K_KIND_NULL; + alpha_evax_proc->pdsckind = PDSC_S_K_KIND_NULL; else { + (void) restore_line_pointer (name_end); as_fatal (_("unknown procedure kind")); demand_empty_rest_of_line (); return; } - *input_line_pointer = name_end; + (void) restore_line_pointer (name_end); demand_empty_rest_of_line (); #ifdef md_flush_pending_output @@ -4060,67 +4574,73 @@ s_alpha_pdesc (int ignore ATTRIBUTE_UNUSED) p = frag_more (16); fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0); fixp->fx_done = 1; - seginfo->literal_pool_size += 16; - *p = alpha_evax_proc.pdsckind - | ((alpha_evax_proc.framereg == 29) ? PDSC_S_M_BASE_REG_IS_FP : 0); + *p = alpha_evax_proc->pdsckind + | ((alpha_evax_proc->framereg == 29) ? PDSC_S_M_BASE_REG_IS_FP : 0) + | ((alpha_evax_proc->handler) ? PDSC_S_M_HANDLER_VALID : 0) + | ((alpha_evax_proc->handler_data) ? PDSC_S_M_HANDLER_DATA_VALID : 0); *(p + 1) = PDSC_S_M_NATIVE | PDSC_S_M_NO_JACKET; - switch (alpha_evax_proc.pdsckind) + switch (alpha_evax_proc->pdsckind) { case PDSC_S_K_KIND_NULL: *(p + 2) = 0; *(p + 3) = 0; break; case PDSC_S_K_KIND_FP_REGISTER: - *(p + 2) = alpha_evax_proc.fp_save; - *(p + 3) = alpha_evax_proc.ra_save; + *(p + 2) = alpha_evax_proc->fp_save; + *(p + 3) = alpha_evax_proc->ra_save; break; case PDSC_S_K_KIND_FP_STACK: - md_number_to_chars (p + 2, (valueT) alpha_evax_proc.rsa_offset, 2); + md_number_to_chars (p + 2, (valueT) alpha_evax_proc->rsa_offset, 2); break; default: /* impossible */ break; } *(p + 4) = 0; - *(p + 5) = alpha_evax_proc.type & 0x0f; + *(p + 5) = alpha_evax_proc->type & 0x0f; /* Signature offset. */ md_number_to_chars (p + 6, (valueT) 0, 2); - fix_new_exp (frag_now, p - frag_now->fr_literal+8, 8, &exp, 0, BFD_RELOC_64); + fix_new_exp (frag_now, p - frag_now->fr_literal + 8, + 8, &exp, 0, BFD_RELOC_64); - if (alpha_evax_proc.pdsckind == PDSC_S_K_KIND_NULL) + if (alpha_evax_proc->pdsckind == PDSC_S_K_KIND_NULL) return; - /* Add dummy fix to make add_to_link_pool work. */ - p = frag_more (8); - fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0); - fixp->fx_done = 1; - seginfo->literal_pool_size += 8; - /* pdesc+16: Size. */ - md_number_to_chars (p, (valueT) alpha_evax_proc.framesize, 4); - + p = frag_more (6); + md_number_to_chars (p, (valueT) alpha_evax_proc->framesize, 4); md_number_to_chars (p + 4, (valueT) 0, 2); /* Entry length. */ - md_number_to_chars (p + 6, alpha_evax_proc.prologue, 2); + exp.X_op = O_subtract; + exp.X_add_symbol = alpha_prologue_label; + exp.X_op_symbol = entry_sym; + emit_expr (&exp, 2); - if (alpha_evax_proc.pdsckind == PDSC_S_K_KIND_FP_REGISTER) + if (alpha_evax_proc->pdsckind == PDSC_S_K_KIND_FP_REGISTER) return; - /* Add dummy fix to make add_to_link_pool work. */ + /* pdesc+24: register masks. */ p = frag_more (8); - fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0); - fixp->fx_done = 1; - seginfo->literal_pool_size += 8; + md_number_to_chars (p, alpha_evax_proc->imask, 4); + md_number_to_chars (p + 4, alpha_evax_proc->fmask, 4); - /* pdesc+24: register masks. */ + if (alpha_evax_proc->handler) + { + p = frag_more (8); + fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, + alpha_evax_proc->handler, 0, 0, BFD_RELOC_64); + } - md_number_to_chars (p, alpha_evax_proc.imask, 4); - md_number_to_chars (p + 4, alpha_evax_proc.fmask, 4); + if (alpha_evax_proc->handler_data) + { + p = frag_more (8); + md_number_to_chars (p, alpha_evax_proc->handler_data, 8); + } } /* Support for crash debug on vms. */ @@ -4130,7 +4650,6 @@ s_alpha_name (int ignore ATTRIBUTE_UNUSED) { char *p; expressionS exp; - segment_info_type *seginfo = seg_info (alpha_link_section); if (now_seg != alpha_link_section) { @@ -4155,16 +4674,19 @@ s_alpha_name (int ignore ATTRIBUTE_UNUSED) frag_align (3, 0, 0); p = frag_more (8); - seginfo->literal_pool_size += 8; fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &exp, 0, BFD_RELOC_64); } +/* Parse .linkage . + Create a linkage pair relocation. */ + static void s_alpha_linkage (int ignore ATTRIBUTE_UNUSED) { expressionS exp; char *p; + fixS *fixp; #ifdef md_flush_pending_output md_flush_pending_output (); @@ -4177,14 +4699,37 @@ s_alpha_linkage (int ignore ATTRIBUTE_UNUSED) } else { + struct alpha_linkage_fixups *linkage_fixup; + p = frag_more (LKP_S_K_SIZE); memset (p, 0, LKP_S_K_SIZE); - fix_new_exp (frag_now, p - frag_now->fr_literal, LKP_S_K_SIZE, &exp, 0,\ - BFD_RELOC_ALPHA_LINKAGE); + fixp = fix_new_exp + (frag_now, p - frag_now->fr_literal, LKP_S_K_SIZE, &exp, 0, + BFD_RELOC_ALPHA_LINKAGE); + + if (alpha_insn_label == NULL) + alpha_insn_label = symbol_new + (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now); + + /* Create a linkage element. */ + linkage_fixup = XNEW (struct alpha_linkage_fixups); + linkage_fixup->fixp = fixp; + linkage_fixup->next = NULL; + linkage_fixup->label = alpha_insn_label; + + /* Append it to the list. */ + if (alpha_linkage_fixup_root == NULL) + alpha_linkage_fixup_root = linkage_fixup; + else + alpha_linkage_fixup_tail->next = linkage_fixup; + alpha_linkage_fixup_tail = linkage_fixup; } demand_empty_rest_of_line (); } +/* Parse .code_address . + Create a code address relocation. */ + static void s_alpha_code_address (int ignore ATTRIBUTE_UNUSED) { @@ -4211,8 +4756,7 @@ s_alpha_code_address (int ignore ATTRIBUTE_UNUSED) static void s_alpha_fp_save (int ignore ATTRIBUTE_UNUSED) { - - alpha_evax_proc.fp_save = tc_get_register (1); + alpha_evax_proc->fp_save = tc_get_register (1); demand_empty_rest_of_line (); } @@ -4229,7 +4773,7 @@ s_alpha_mask (int ignore ATTRIBUTE_UNUSED) } else { - alpha_evax_proc.imask = val; + alpha_evax_proc->imask = val; (void) get_absolute_expression (); } demand_empty_rest_of_line (); @@ -4247,7 +4791,7 @@ s_alpha_fmask (int ignore ATTRIBUTE_UNUSED) } else { - alpha_evax_proc.fmask = val; + alpha_evax_proc->fmask = val; (void) get_absolute_expression (); } demand_empty_rest_of_line (); @@ -4256,12 +4800,13 @@ s_alpha_fmask (int ignore ATTRIBUTE_UNUSED) static void s_alpha_end (int ignore ATTRIBUTE_UNUSED) { + char *name; char c; - c = get_symbol_end (); - *input_line_pointer = c; + c = get_symbol_name (&name); + (void) restore_line_pointer (c); demand_empty_rest_of_line (); - alpha_evax_proc.symbol = 0; + alpha_evax_proc = NULL; } static void @@ -4390,12 +4935,11 @@ s_alpha_proc (int is_static ATTRIBUTE_UNUSED) /* Takes ".proc name,nargs". */ SKIP_WHITESPACE (); - name = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (&name); p = input_line_pointer; symbolP = symbol_find_or_make (name); *p = c; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); if (*input_line_pointer != ',') { *p = 0; @@ -4410,6 +4954,7 @@ s_alpha_proc (int is_static ATTRIBUTE_UNUSED) temp = get_absolute_expression (); } /* *symbol_get_obj (symbolP) = (signed char) temp; */ + (void) symbolP; as_warn (_("unhandled: .proc %s,%d"), name, temp); demand_empty_rest_of_line (); } @@ -4424,9 +4969,8 @@ s_alpha_set (int x ATTRIBUTE_UNUSED) int yesno = 1; SKIP_WHITESPACE (); - name = input_line_pointer; - ch = get_symbol_end (); + ch = get_symbol_name (&name); s = name; if (s[0] == 'n' && s[1] == 'o') { @@ -4446,7 +4990,7 @@ s_alpha_set (int x ATTRIBUTE_UNUSED) else as_warn (_("Tried to .set unrecognized mode `%s'"), name); - *input_line_pointer = ch; + (void) restore_line_pointer (ch); demand_empty_rest_of_line (); } @@ -4485,7 +5029,7 @@ s_alpha_align (int ignore ATTRIBUTE_UNUSED) { int align; char fill, *pfill; - long max_alignment = 15; + long max_alignment = 16; align = get_absolute_expression (); if (align > max_alignment) @@ -4511,12 +5055,13 @@ s_alpha_align (int ignore ATTRIBUTE_UNUSED) if (align != 0) { alpha_auto_align_on = 1; - alpha_align (align, pfill, alpha_insn_label, 1); + alpha_align (align, pfill, NULL, 1); } else { alpha_auto_align_on = 0; } + alpha_insn_label = NULL; demand_empty_rest_of_line (); } @@ -4580,8 +5125,8 @@ s_alpha_arch (int ignored ATTRIBUTE_UNUSED) const struct cpu_type *p; SKIP_WHITESPACE (); - name = input_line_pointer; - ch = get_symbol_end (); + + ch = get_symbol_name (&name); for (p = cpu_types; p->name; ++p) if (strcmp (name, p->name) == 0) @@ -4589,10 +5134,10 @@ s_alpha_arch (int ignored ATTRIBUTE_UNUSED) alpha_target_name = p->name, alpha_target = p->flags; goto found; } - as_warn ("Unknown CPU identifier `%s'", name); + as_warn (_("Unknown CPU identifier `%s'"), name); found: - *input_line_pointer = ch; + (void) restore_line_pointer (ch); demand_empty_rest_of_line (); } @@ -4612,12 +5157,12 @@ alpha_print_token (FILE *f, const expressionS *exp) { expressionS nexp = *exp; nexp.X_op = O_register; - print_expr (f, &nexp); + print_expr_1 (f, &nexp); } putc (')', f); break; default: - print_expr (f, exp); + print_expr_1 (f, exp); break; } } @@ -4643,22 +5188,26 @@ const pseudo_typeS md_pseudo_table[] = {"sect.s", s_alpha_section, 0}, #endif #ifdef OBJ_EVAX - { "pdesc", s_alpha_pdesc, 0}, - { "name", s_alpha_name, 0}, - { "linkage", s_alpha_linkage, 0}, - { "code_address", s_alpha_code_address, 0}, - { "ent", s_alpha_ent, 0}, - { "frame", s_alpha_frame, 0}, - { "fp_save", s_alpha_fp_save, 0}, - { "mask", s_alpha_mask, 0}, - { "fmask", s_alpha_fmask, 0}, - { "end", s_alpha_end, 0}, - { "file", s_alpha_file, 0}, - { "rdata", s_alpha_section, 1}, - { "comm", s_alpha_comm, 0}, - { "link", s_alpha_section, 3}, - { "ctors", s_alpha_section, 4}, - { "dtors", s_alpha_section, 5}, + {"section", s_alpha_section, 0}, + {"literals", s_alpha_literals, 0}, + {"pdesc", s_alpha_pdesc, 0}, + {"name", s_alpha_name, 0}, + {"linkage", s_alpha_linkage, 0}, + {"code_address", s_alpha_code_address, 0}, + {"ent", s_alpha_ent, 0}, + {"frame", s_alpha_frame, 0}, + {"fp_save", s_alpha_fp_save, 0}, + {"mask", s_alpha_mask, 0}, + {"fmask", s_alpha_fmask, 0}, + {"end", s_alpha_end, 0}, + {"file", s_alpha_file, 0}, + {"rdata", s_alpha_section, 1}, + {"comm", s_alpha_comm, 0}, + {"link", s_alpha_section, 3}, + {"ctors", s_alpha_section, 4}, + {"dtors", s_alpha_section, 5}, + {"handler", s_alpha_handler, 0}, + {"handler_data", s_alpha_handler, 1}, #endif #ifdef OBJ_ELF /* Frame related pseudos. */ @@ -4682,8 +5231,12 @@ const pseudo_typeS md_pseudo_table[] = {"scl", s_alpha_coff_wrapper, 5}, {"tag", s_alpha_coff_wrapper, 6}, {"val", s_alpha_coff_wrapper, 7}, +#else +#ifdef OBJ_EVAX + {"prologue", s_alpha_prologue, 0}, #else {"prologue", s_ignore, 0}, +#endif #endif {"gprel32", s_alpha_gprel32, 0}, {"t_floating", s_alpha_float_cons, 'd'}, @@ -4747,7 +5300,7 @@ maybe_set_gp (asection *sec) if (!sec) return; - vma = bfd_get_section_vma (foo, sec); + vma = bfd_get_section_vma (sec->owner, sec); if (vma && vma < alpha_gp_value) alpha_gp_value = vma; } @@ -4755,7 +5308,7 @@ maybe_set_gp (asection *sec) static void select_gp_value (void) { - assert (alpha_gp_value == 0); + gas_assert (alpha_gp_value == 0); /* Get minus-one in whatever width... */ alpha_gp_value = 0; @@ -4780,20 +5333,20 @@ select_gp_value (void) #ifdef OBJ_ELF /* Map 's' to SHF_ALPHA_GPREL. */ -int -alpha_elf_section_letter (int letter, char **ptr_msg) +bfd_vma +alpha_elf_section_letter (int letter, const 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"); + *ptr_msg = _("bad .section directive: want a,s,w,x,M,S,G,T in string"); return -1; } /* Map SHF_ALPHA_GPREL to SEC_SMALL_DATA. */ flagword -alpha_elf_section_flags (flagword flags, int attr, int type ATTRIBUTE_UNUSED) +alpha_elf_section_flags (flagword flags, bfd_vma attr, int type ATTRIBUTE_UNUSED) { if (attr & SHF_ALPHA_GPREL) flags |= SEC_SMALL_DATA; @@ -4807,8 +5360,8 @@ alpha_elf_section_flags (flagword flags, int attr, int type ATTRIBUTE_UNUSED) void alpha_handle_align (fragS *fragp) { - static char const unop[4] = { 0x00, 0x00, 0xfe, 0x2f }; - static char const nopunop[8] = + static unsigned char const unop[4] = { 0x00, 0x00, 0xfe, 0x2f }; + static unsigned char const nopunop[8] = { 0x1f, 0x04, 0xff, 0x47, 0x00, 0x00, 0xfe, 0x2f @@ -4862,7 +5415,7 @@ md_begin (void) expressionS e; e.X_op = O_max; - assert (e.X_op == O_max); + gas_assert (e.X_op == O_max); } /* Create the opcode hash table. */ @@ -4885,7 +5438,7 @@ md_begin (void) if ((slash = strchr (name, '/')) != NULL) { - char *p = xmalloc (strlen (name)); + char *p = XNEWVEC (char, strlen (name)); memcpy (p, name, slash - name); strcpy (p + (slash - name), slash + 1); @@ -5020,10 +5573,10 @@ md_section_align (segT seg, valueT size) of LITTLENUMS emitted is stored in *SIZEP. An error message is returned, or NULL on OK. */ -char * +const char * md_atof (int type, char *litP, int *sizeP) { - extern char *vax_md_atof (int, char *, int *); + extern const char *vax_md_atof (int, char *, int *); switch (type) { @@ -5031,6 +5584,7 @@ md_atof (int type, char *litP, int *sizeP) case 'G': /* vax_md_atof() doesn't like "G" for some reason. */ type = 'g'; + /* Fall through. */ case 'F': case 'D': return vax_md_atof (type, litP, sizeP); @@ -5043,7 +5597,7 @@ md_atof (int type, char *litP, int *sizeP) /* Take care of the target-specific command-line options. */ int -md_parse_option (int c, char *arg) +md_parse_option (int c, const char *arg) { switch (c) { @@ -5089,6 +5643,14 @@ md_parse_option (int c, char *arg) case 'h': /* For gnu-c/vax compatibility. */ break; + + case OPTION_REPLACE: + alpha_flag_replace = 1; + break; + + case OPTION_NOREPLACE: + alpha_flag_replace = 0; + break; #endif case OPTION_RELAX: @@ -5128,8 +5690,9 @@ Alpha options:\n\ #ifdef OBJ_EVAX fputs (_("\ VMS options:\n\ --+ hash encode (don't truncate) names longer than 64 characters\n\ --H show new symbol after hash truncation\n"), +-+ encode (don't truncate) names longer than 64 characters\n\ +-H show new symbol after hash truncation\n\ +-replace/-noreplace enable or disable the optimization of procedure calls\n"), stream); #endif } @@ -5233,7 +5796,7 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg) #ifdef OBJ_ECOFF case BFD_RELOC_GPREL32: - assert (fixP->fx_subsy == alpha_gp_symbol); + gas_assert (fixP->fx_subsy == alpha_gp_symbol); fixP->fx_subsy = 0; /* FIXME: inherited this obliviousness of `value' -- why? */ md_number_to_chars (fixpos, -alpha_gp_value, 4); @@ -5294,6 +5857,79 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg) case BFD_RELOC_ALPHA_CODEADDR: return; +#ifdef OBJ_EVAX + case BFD_RELOC_ALPHA_NOP: + value -= (8 + 4); /* PC-relative, base is jsr+4. */ + + /* From B.4.5.2 of the OpenVMS Linker Utility Manual: + "Finally, the ETIR$C_STC_BSR command passes the same address + as ETIR$C_STC_NOP (so that they will fail or succeed together), + and the same test is done again." */ + if (S_GET_SEGMENT (fixP->fx_addsy) == undefined_section) + { + fixP->fx_addnumber = -value; + return; + } + + if ((abs (value) >> 2) & ~0xfffff) + goto done; + else + { + /* Change to a nop. */ + image = 0x47FF041F; + goto write_done; + } + + case BFD_RELOC_ALPHA_LDA: + /* fixup_segment sets fixP->fx_addsy to NULL when it can pre-compute + the value for an O_subtract. */ + if (fixP->fx_addsy + && S_GET_SEGMENT (fixP->fx_addsy) == undefined_section) + { + fixP->fx_addnumber = symbol_get_bfdsym (fixP->fx_subsy)->value; + return; + } + + if ((abs (value)) & ~0x7fff) + goto done; + else + { + /* Change to an lda. */ + image = 0x237B0000 | (value & 0xFFFF); + goto write_done; + } + + case BFD_RELOC_ALPHA_BSR: + case BFD_RELOC_ALPHA_BOH: + value -= 4; /* PC-relative, base is jsr+4. */ + + /* See comment in the BFD_RELOC_ALPHA_NOP case above. */ + if (S_GET_SEGMENT (fixP->fx_addsy) == undefined_section) + { + fixP->fx_addnumber = -value; + return; + } + + if ((abs (value) >> 2) & ~0xfffff) + { + /* Out of range. */ + if (fixP->fx_r_type == BFD_RELOC_ALPHA_BOH) + { + /* Add a hint. */ + image = bfd_getl32(fixpos); + image = (image & ~0x3FFF) | ((value >> 2) & 0x3FFF); + goto write_done; + } + goto done; + } + else + { + /* Change to a branch. */ + image = 0xD3400000 | ((value >> 2) & 0x1FFFFF); + goto write_done; + } +#endif + case BFD_RELOC_VTABLE_INHERIT: case BFD_RELOC_VTABLE_ENTRY: return; @@ -5306,7 +5942,7 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg) as_fatal (_("unhandled relocation type %s"), bfd_get_reloc_code_name (fixP->fx_r_type)); - assert (-(int) fixP->fx_r_type < (int) alpha_num_operands); + gas_assert (-(int) fixP->fx_r_type < (int) alpha_num_operands); operand = &alpha_operands[-(int) fixP->fx_r_type]; /* The rest of these fixups only exist internally during symbol @@ -5463,6 +6099,12 @@ alpha_force_relocation (fixS *f) case BFD_RELOC_ALPHA_TPREL_HI16: case BFD_RELOC_ALPHA_TPREL_LO16: case BFD_RELOC_ALPHA_TPREL16: +#ifdef OBJ_EVAX + case BFD_RELOC_ALPHA_NOP: + case BFD_RELOC_ALPHA_BSR: + case BFD_RELOC_ALPHA_LDA: + case BFD_RELOC_ALPHA_BOH: +#endif return 1; default: @@ -5502,6 +6144,7 @@ alpha_fix_adjustable (fixS *f) case BFD_RELOC_ALPHA_GPREL_HI16: case BFD_RELOC_ALPHA_GPREL_LO16: case BFD_RELOC_23_PCREL_S2: + case BFD_RELOC_16: case BFD_RELOC_32: case BFD_RELOC_64: case BFD_RELOC_ALPHA_HINT: @@ -5555,6 +6198,13 @@ alpha_fix_adjustable (fixS *f) return 1; } #endif +#ifdef OBJ_EVAX + case BFD_RELOC_ALPHA_NOP: + case BFD_RELOC_ALPHA_BSR: + case BFD_RELOC_ALPHA_LDA: + case BFD_RELOC_ALPHA_BOH: + return 1; +#endif default: return 1; @@ -5570,14 +6220,14 @@ tc_gen_reloc (asection *sec ATTRIBUTE_UNUSED, { arelent *reloc; - reloc = xmalloc (sizeof (* reloc)); - reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); + reloc = XNEW (arelent); + reloc->sym_ptr_ptr = XNEW (asymbol *); *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; /* Make sure none of our internal relocations make it this far. They'd better have been fully resolved by this point. */ - assert ((int) fixp->fx_r_type > 0); + gas_assert ((int) fixp->fx_r_type > 0); reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); if (reloc->howto == NULL) @@ -5592,28 +6242,73 @@ tc_gen_reloc (asection *sec ATTRIBUTE_UNUSED, as_fatal (_("internal error? cannot generate `%s' relocation"), bfd_get_reloc_code_name (fixp->fx_r_type)); - assert (!fixp->fx_pcrel == !reloc->howto->pc_relative); + gas_assert (!fixp->fx_pcrel == !reloc->howto->pc_relative); + + reloc->addend = fixp->fx_offset; #ifdef OBJ_ECOFF + /* Fake out bfd_perform_relocation. sigh. */ + /* ??? Better would be to use the special_function hook. */ if (fixp->fx_r_type == BFD_RELOC_ALPHA_LITERAL) - /* Fake out bfd_perform_relocation. sigh. */ reloc->addend = -alpha_gp_value; - else #endif + +#ifdef OBJ_EVAX + switch (fixp->fx_r_type) { - 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_EXTERNAL (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 + struct evax_private_udata_struct *udata; + const char *pname; + int pname_len; + + case BFD_RELOC_ALPHA_LINKAGE: + /* Copy the linkage index. */ + reloc->addend = fixp->fx_addnumber; + break; + + case BFD_RELOC_ALPHA_NOP: + case BFD_RELOC_ALPHA_BSR: + case BFD_RELOC_ALPHA_LDA: + case BFD_RELOC_ALPHA_BOH: + pname = symbol_get_bfdsym (fixp->fx_addsy)->name; + + /* We need the non-suffixed name of the procedure. Beware that + the main symbol might be equated so look it up and take its name. */ + pname_len = strlen (pname); + if (pname_len > 4 && strcmp (pname + pname_len - 4, "..en") == 0) + { + symbolS *sym; + char *my_pname = xmemdup0 (pname, pname_len - 4); + sym = symbol_find (my_pname); + free (my_pname); + if (sym == NULL) + abort (); + + while (symbol_equated_reloc_p (sym)) + { + symbolS *n = symbol_get_value_expression (sym)->X_add_symbol; + + /* We must avoid looping, as that can occur with a badly + written program. */ + if (n == sym) + break; + sym = n; + } + pname = symbol_get_bfdsym (sym)->name; + } + + udata = XNEW (struct evax_private_udata_struct); + udata->enbsym = symbol_get_bfdsym (fixp->fx_addsy); + udata->bsym = symbol_get_bfdsym (fixp->tc_fix_data.info->psym); + udata->origname = (char *)pname; + udata->lkindex = ((struct evax_private_udata_struct *) + symbol_get_bfdsym (fixp->tc_fix_data.info->sym)->udata.p)->lkindex; + reloc->sym_ptr_ptr = (void *)udata; + reloc->addend = fixp->fx_addnumber; + + default: + break; } +#endif return reloc; } @@ -5632,8 +6327,8 @@ tc_get_register (int frame ATTRIBUTE_UNUSED) SKIP_WHITESPACE (); if (*input_line_pointer == '$') { - char *s = input_line_pointer; - char c = get_symbol_end (); + char *s; + char c = get_symbol_name (&s); symbolS *sym = md_undefined_symbol (s); *strchr (s, '\0') = c;