/* tc-alpha.c - Processor-specific code for the DEC Alpha AXP CPU.
- Copyright (C) 1989, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1989, 93-98, 1999 Free Software Foundation, Inc.
Contributed by Carnegie Mellon University, 1993.
Written by Alessandro Forin, based on earlier gas-1.38 target CPU files.
Modified by Ken Raeburn for gas-2.x and ECOFF support.
Modified by Richard Henderson for ELF support.
- Modified by Klaus K"ampf for EVAX (openVMS/Alpha) support.
+ Modified by Klaus K"ampf for EVAX (OpenVMS/Alpha) support.
This file is part of GAS, the GNU Assembler.
#include "as.h"
#include "subsegs.h"
+#include "ecoff.h"
#include "opcode/alpha.h"
/* Two extra symbols we want to see in our input. This is a blatent
misuse of the expressionS.X_op field. */
-#define O_pregister (O_max+1) /* O_register, but in parentheses */
-#define O_cpregister (O_pregister+1) /* + a leading comma */
+#define O_pregister ((operatorT) (O_max+1)) /* O_register, in parentheses */
+#define O_cpregister ((operatorT) (O_pregister+1)) /* + a leading comma */
+#define O_alpha_max ((operatorT) (O_cpregister+1))
/* Macros for extracting the type and number of encoded register tokens */
#endif
#ifdef OBJ_ELF
static void s_alpha_section PARAMS ((int));
+static void s_alpha_ent PARAMS ((int));
+static void s_alpha_end PARAMS ((int));
+static void s_alpha_mask PARAMS ((int));
+static void s_alpha_frame PARAMS ((int));
static void s_alpha_prologue PARAMS ((int));
+static void s_alpha_coff_wrapper PARAMS ((int));
#endif
#ifdef OBJ_EVAX
static void s_alpha_section PARAMS ((int));
{ "32addr", no_argument, NULL, OPTION_32ADDR },
#define OPTION_RELAX (OPTION_32ADDR+1)
{ "relax", no_argument, NULL, OPTION_RELAX },
+#ifdef OBJ_ELF
+#define OPTION_MDEBUG (OPTION_RELAX+1)
+#define OPTION_NO_MDEBUG (OPTION_MDEBUG+1)
+ { "mdebug", no_argument, NULL, OPTION_MDEBUG },
+ { "no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG },
+#endif
{ NULL, no_argument, NULL, 0 }
};
static offsetT alpha_lit8_literal;
#endif
+/* The active .ent symbol. */
+#ifdef OBJ_ELF
+static symbolS *alpha_cur_ent_sym;
+#endif
+
/* Is the assembler not allowed to use $at? */
static int alpha_noat_on = 0;
/* Whether the debugging option was seen. */
static int alpha_debug;
+#ifdef OBJ_ELF
+/* Whether we are emitting an mdebug section. */
+int alpha_flag_mdebug = 1;
+#endif
+
/* Don't fully resolve relocations, allowing code movement in the linker. */
static int alpha_flag_relax;
{ "21066", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
{ "21068", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
{ "21164", AXP_OPCODE_BASE|AXP_OPCODE_EV5 },
- /* Do we have CIX extension here? */
{ "21164a", AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX },
- /* Still same PALcodes? */
{ "21164pc", (AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX
|AXP_OPCODE_MAX) },
- /* All new PALcodes? Extras? */
- { "21264", (AXP_OPCODE_BASE|AXP_OPCODE_BWX
- |AXP_OPCODE_CIX|AXP_OPCODE_MAX) },
+ { "21264", (AXP_OPCODE_BASE|AXP_OPCODE_EV6|AXP_OPCODE_BWX
+ |AXP_OPCODE_MAX|AXP_OPCODE_CIX) },
{ "ev4", AXP_OPCODE_BASE },
{ "ev45", AXP_OPCODE_BASE },
{ "ev5", AXP_OPCODE_BASE },
{ "ev56", AXP_OPCODE_BASE|AXP_OPCODE_BWX },
{ "pca56", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX },
- { "ev6", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_CIX|AXP_OPCODE_MAX },
+ { "ev6", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX|AXP_OPCODE_CIX },
{ "all", AXP_OPCODE_BASE },
{ 0 }
{
unsigned int i;
+ /* Verify that X_op field is wide enough. */
+ {
+ expressionS e;
+ e.X_op = O_alpha_max;
+ assert (e.X_op == O_alpha_max);
+ }
+
/* Create the opcode hash table */
alpha_opcode_hash = hash_new ();
#ifdef OBJ_ELF
if (ECOFF_DEBUGGING)
{
- segT sec;
-
- sec = subseg_new(".mdebug", (subsegT)0);
+ segT sec = subseg_new(".mdebug", (subsegT)0);
bfd_set_section_flags(stdoutput, sec, SEC_HAS_CONTENTS|SEC_READONLY);
bfd_set_section_alignment(stdoutput, sec, 3);
-
-#ifdef ERIC_neverdef
- sec = subseg_new(".reginfo", (subsegT)0);
- /* The ABI says this section should be loaded so that the running
- program can access it. */
- bfd_set_section_flags(stdoutput, sec,
- SEC_ALLOC|SEC_LOAD|SEC_READONLY|SEC_DATA);
- bfd_set_section_alignement(stdoutput, sec, 3);
-#endif
}
#endif /* OBJ_ELF */
int ntok, opnamelen, trunclen;
/* split off the opcode */
- opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_/48");
+ opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_/468");
trunclen = (opnamelen < sizeof (opname) - 1
? opnamelen
: sizeof (opname) - 1);
alpha_flag_relax = 1;
break;
+#ifdef OBJ_ELF
+ case OPTION_MDEBUG:
+ alpha_flag_mdebug = 1;
+ break;
+ case OPTION_NO_MDEBUG:
+ alpha_flag_mdebug = 0;
+ break;
+#endif
+
default:
return 0;
}
Alpha options:\n\
-32addr treat addresses as 32-bit values\n\
-F lack floating point instructions support\n\
--m21064 | -m21066 | -m21164 | -m21164a\n\
--mev4 | -mev45 | -mev5 | -mev56 | -mall\n\
- specify variant of Alpha architecture\n"),
+-mev4 | -mev45 | -mev5 | -mev56 | -mpca56 | -mev6 | -mall\n\
+ specify variant of Alpha architecture\n\
+-m21064 | -m21066 | -m21164 | -m21164a | -m21164pc | -m21264\n\
+ these variants include PALcode opcodes\n"),
stream);
#ifdef OBJ_EVAX
fputs (_("\
#endif
do_reloc_gp:
- fixP->fx_addsy = section_symbol (absolute_section);
+ fixP->fx_addsy = section_symbol (now_seg);
md_number_to_chars (fixpos, value, 2);
break;
Therefore they must be completely resolved as constants. */
if (fixP->fx_addsy != 0
- && fixP->fx_addsy->bsym->section != absolute_section)
+ && S_GET_SEGMENT (fixP->fx_addsy) != absolute_section)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("non-absolute expression in constant field"));
{
#ifdef OBJ_ELF
/* Prevent all adjustments to global symbols */
- if (S_IS_EXTERN (f->fx_addsy))
+ if (S_IS_EXTERN (f->fx_addsy) || S_IS_WEAK (f->fx_addsy))
return 0;
#endif
arelent *reloc;
reloc = (arelent *) xmalloc (sizeof (arelent));
- reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+ reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
/* Make sure none of our internal relocations make it this far.
* 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_COMMON(fixp->fx_addsy))
- reloc->addend -= fixp->fx_addsy->bsym->value;
+ if ((S_IS_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy))
+ && !S_IS_COMMON(fixp->fx_addsy))
+ reloc->addend -= symbol_get_bfdsym (fixp->fx_addsy)->value;
#endif
}
case O_pregister:
case O_cpregister:
goto match_failed;
+
+ default:
+ break;
}
break;
case O_pregister:
case O_cpregister:
goto match_failed;
+
+ default:
+ break;
}
++tokidx;
break;
/* Apply the fixups in order */
for (i = 0; i < insn->nfixups; ++i)
{
+ const struct alpha_operand *operand;
struct alpha_fixup *fixup = &insn->fixups[i];
int size, pcrel;
fixS *fixP;
/* Some fixups are only used internally and so have no howto */
if ((int)fixup->reloc < 0)
- size = 4, pcrel = 0;
+ {
+ operand = &alpha_operands[-(int)fixup->reloc];
+ size = 4;
+ pcrel = ((operand->flags & AXP_OPERAND_RELATIVE) != 0);
+ }
#ifdef OBJ_ELF
/* These relocation types are only used internally. */
else if (fixup->reloc == BFD_RELOC_ALPHA_GPDISP_HI16
case BFD_RELOC_GPREL32:
fixP->fx_no_overflow = 1;
break;
+
default:
+ if ((int)fixup->reloc < 0)
+ {
+ if (operand->flags & AXP_OPERAND_NOOVERFLOW)
+ fixP->fx_no_overflow = 1;
+ }
break;
}
}
expressionS newtok[3];
expressionS addend;
- /* We're going to need this symbol in md_apply_fix(). */
- (void) section_symbol (absolute_section);
-
#ifdef OBJ_ECOFF
if (regno (tok[2].X_add_number) == AXP_REG_PV)
ecoff_set_gp_prolog_size (0);
addend = tok[1];
#ifdef OBJ_ECOFF
- assert (addend.X_op == O_constant);
+ if (addend.X_op != O_constant)
+ as_bad (_("can not resolve expression"));
addend.X_op = O_symbol;
addend.X_add_symbol = alpha_gp_symbol;
#endif
segment_info_type *seginfo = seg_info (alpha_link_section);
fixS *fixp;
- offset = -basesym->sy_obj;
+ offset = - *symbol_get_obj (basesym);
/* @@ This assumes all entries in a given section will be of the same
size... Probably correct, but unwise to rely on. */
/* XXX: Disable this .got minimizing optimization so that we can get
better instruction offset knowledge in the compiler. This happens
very infrequently anyway. */
- if (1 || !range_signed_32 (addend)
- && (alpha_noat_on || targreg == AXP_REG_AT))
+ if (1 || (!range_signed_32 (addend)
+ && (alpha_noat_on || targreg == AXP_REG_AT)))
{
newtok[1] = *exp;
addend = 0;
break;
default:
- abort();
+ as_bad (_("can't handle expression"));
+ addend = 0;
+ break;
}
if (!range_signed_32 (addend))
}
insn.nfixups++;
insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE;
- insn.fixups[0].exp.X_op = O_constant;
+ 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 = 1;
emit_lituse = 0;
}
insn.nfixups++;
insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE;
- insn.fixups[0].exp.X_op = O_constant;
+ 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 = 1;
}
}
insn.nfixups++;
insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE;
- insn.fixups[0].exp.X_op = O_constant;
+ 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 = 1;
}
}
insn.nfixups++;
insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE;
- insn.fixups[0].exp.X_op = O_constant;
+ 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 = 3;
}
*p = 0;
symbolP = symbol_find_or_make (name);
- *p = c;
#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"));
p = frag_more (temp);
new_seg->flags |= SEC_IS_COMMON;
if (! S_IS_DEFINED (symbolP))
- symbolP->bsym->section = new_seg;
+ S_SET_SEGMENT (symbolP, new_seg);
#else
S_SET_VALUE (symbolP, (valueT) temp);
#endif
subseg_set (current_section, current_subsec);
#endif
- know (symbolP->sy_frag == &zero_address_frag);
+ know (symbol_get_frag (symbolP) == &zero_address_frag);
demand_empty_rest_of_line ();
}
alpha_current_align = 0;
}
+static void
+s_alpha_ent (dummy)
+ int dummy;
+{
+ if (ECOFF_DEBUGGING)
+ ecoff_directive_ent (0);
+ else
+ {
+ char *name, name_end;
+ name = input_line_pointer;
+ name_end = get_symbol_end ();
+
+ if (! is_name_beginner (*name))
+ {
+ as_warn (_(".ent directive has no name"));
+ *input_line_pointer = name_end;
+ }
+ else
+ {
+ symbolS *sym;
+
+ if (alpha_cur_ent_sym)
+ as_warn (_("nested .ent directives"));
+
+ sym = symbol_find_or_make (name);
+ symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
+ alpha_cur_ent_sym = sym;
+
+ /* The .ent directive is sometimes followed by a number. Not sure
+ what it really means, but ignore it. */
+ *input_line_pointer = name_end;
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer == ',')
+ {
+ input_line_pointer++;
+ SKIP_WHITESPACE ();
+ }
+ if (isdigit (*input_line_pointer) || *input_line_pointer == '-')
+ (void) get_absolute_expression ();
+ }
+ demand_empty_rest_of_line ();
+ }
+}
+
+static void
+s_alpha_end (dummy)
+ int dummy;
+{
+ if (ECOFF_DEBUGGING)
+ ecoff_directive_end (0);
+ else
+ {
+ char *name, name_end;
+ name = input_line_pointer;
+ name_end = get_symbol_end ();
+
+ if (! is_name_beginner (*name))
+ {
+ as_warn (_(".end directive has no name"));
+ *input_line_pointer = name_end;
+ }
+ else
+ {
+ symbolS *sym;
+
+ sym = symbol_find (name);
+ if (sym != alpha_cur_ent_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;
+ }
+
+ alpha_cur_ent_sym = NULL;
+
+ *input_line_pointer = name_end;
+ }
+ demand_empty_rest_of_line ();
+ }
+}
+
+static void
+s_alpha_mask (fp)
+ int fp;
+{
+ if (ECOFF_DEBUGGING)
+ {
+ if (fp)
+ ecoff_directive_fmask (0);
+ else
+ ecoff_directive_mask (0);
+ }
+ else
+ discard_rest_of_line ();
+}
+
+static void
+s_alpha_frame (dummy)
+ int dummy;
+{
+ if (ECOFF_DEBUGGING)
+ ecoff_directive_frame (0);
+ else
+ discard_rest_of_line ();
+}
+
static void
s_alpha_prologue (ignore)
int ignore;
arg = get_absolute_expression ();
demand_empty_rest_of_line ();
- sym = ecoff_get_cur_proc_sym ();
+ if (ECOFF_DEBUGGING)
+ sym = ecoff_get_cur_proc_sym ();
+ else
+ sym = alpha_cur_ent_sym;
know (sym != NULL);
switch (arg)
}
}
-#endif
+static void
+s_alpha_coff_wrapper (which)
+ int which;
+{
+ static void (* const fns[]) PARAMS ((int)) = {
+ ecoff_directive_begin,
+ ecoff_directive_bend,
+ ecoff_directive_def,
+ ecoff_directive_dim,
+ ecoff_directive_endef,
+ ecoff_directive_file,
+ ecoff_directive_scl,
+ ecoff_directive_tag,
+ ecoff_directive_val,
+ ecoff_directive_loc,
+ };
+
+ assert (which >= 0 && which < sizeof(fns)/sizeof(*fns));
+
+ if (ECOFF_DEBUGGING)
+ (*fns[which])(0);
+ else
+ {
+ as_bad (_("ECOFF debugging is disabled."));
+ ignore_rest_of_line ();
+ }
+}
+#endif /* OBJ_ELF */
#ifdef OBJ_EVAX
}
symbol = make_expr_symbol (&symexpr);
- symbol->bsym->flags |= BSF_FUNCTION;
+ symbol_get_bfdsym (symbol)->flags |= BSF_FUNCTION;
alpha_evax_proc.symbol = symbol;
demand_empty_rest_of_line ();
return;
}
- alpha_evax_proc.symbol->sy_obj = (valueT)seginfo->literal_pool_size;
+ *symbol_get_obj (alpha_evax_proc.symbol) =
+ (valueT) seginfo->literal_pool_size;
expression (&exp);
if (exp.X_op != O_symbol)
entry_sym = make_expr_symbol (&exp);
/* Save bfd symbol of proc desc in function symbol. */
- alpha_evax_proc.symbol->bsym->udata.p = (PTR)entry_sym->bsym;
+ symbol_get_bfdsym (alpha_evax_proc.symbol)->udata.p
+ = symbol_get_bfdsym (entry_sym);
SKIP_WHITESPACE ();
if (*input_line_pointer++ != ',')
extern char *demand_copy_string PARAMS ((int *lenP));
sprintf (case_hack, "<CASE:%01d%01d>",
- alpha_flag_hash_long_names, alpha_flag_show_after_trunc);
+ alpha_flag_hash_long_names, alpha_flag_show_after_trunc);
s = symbol_find_or_make (case_hack);
- s->bsym->flags |= BSF_FILE;
+ symbol_get_bfdsym (s)->flags |= BSF_FILE;
get_absolute_expression ();
s = symbol_find_or_make (demand_copy_string (&length));
- s->bsym->flags |= BSF_FILE;
+ symbol_get_bfdsym (s)->flags |= BSF_FILE;
demand_empty_rest_of_line ();
return;
input_line_pointer++;
temp = get_absolute_expression ();
}
- /* symbolP->sy_other = (signed char) temp; */
+ /* *symbol_get_obj (symbolP) = (signed char) temp; */
as_warn (_("unhandled: .proc %s,%d"), name, temp);
demand_empty_rest_of_line ();
}
{ "dtors", s_alpha_section, 5},
#endif
#ifdef OBJ_ELF
+ /* Frame related pseudos. */
+ {"ent", s_alpha_ent, 0},
+ {"end", s_alpha_end, 0},
+ {"mask", s_alpha_mask, 0},
+ {"fmask", s_alpha_mask, 1},
+ {"frame", s_alpha_frame, 0},
{"prologue", s_alpha_prologue, 0},
+ /* COFF debugging related pseudos. */
+ {"begin", s_alpha_coff_wrapper, 0},
+ {"bend", s_alpha_coff_wrapper, 1},
+ {"def", s_alpha_coff_wrapper, 2},
+ {"dim", s_alpha_coff_wrapper, 3},
+ {"endef", s_alpha_coff_wrapper, 4},
+ {"file", s_alpha_coff_wrapper, 5},
+ {"scl", s_alpha_coff_wrapper, 6},
+ {"tag", s_alpha_coff_wrapper, 7},
+ {"val", s_alpha_coff_wrapper, 8},
+ {"loc", s_alpha_coff_wrapper, 9},
#else
{"prologue", s_ignore, 0},
#endif
if (label != NULL)
{
assert (S_GET_SEGMENT (label) == now_seg);
- label->sy_frag = frag_now;
+ symbol_set_frag (label, frag_now);
S_SET_VALUE (label, (valueT) frag_now_fix ());
}