/* 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 Free Software Foundation, Inc.
+ Copyright (C) 1989-2017 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.
#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"
\f
#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
MACRO_OPIR,
MACRO_CPIR,
MACRO_FPR,
- MACRO_EXP,
+ MACRO_EXP
};
struct alpha_macro
/* 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:";
#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 }
};
#undef AXP_REG_GP
#define AXP_REG_GP AXP_REG_PV
+
#endif /* OBJ_EVAX */
/* The cpu for which we are generating code. */
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
#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
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. */
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;
#ifdef OBJ_EVAX
/* Collect information about current procedure here. */
-static struct
+struct alpha_evax_procs
{
symbolS *symbol; /* Proc pdesc symbol. */
int pdsckind;
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 */
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. */
}
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 #. */
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
\f
static struct alpha_reloc_tag *
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,
present. Not implemented.
Also suppress the optimization if the !literals/!lituses are spread
- in different segments. This can happen with "intersting" uses of
+ in different segments. This can happen with "interesting" uses of
inline assembly; examples are present in the Linux kernel semaphores. */
for (fixp = seginfo->fix_root; fixp; fixp = next)
if (alpha_literal_hash)
bfd_map_over_sections (stdoutput, alpha_adjust_relocs, NULL);
}
+
+#endif
\f
#ifdef DEBUG_ALPHA
static void
++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;
}
*input_line_pointer = c;
- SKIP_WHITESPACE ();
+ SKIP_WHITESPACE_AFTER_NAME ();
if (*input_line_pointer != '!')
{
if (r->require_seq)
/* ... then fall through to plain expression. */
input_line_pointer = hold;
}
+ /* Fall through. */
default:
if (saw_arg && !saw_comma)
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;
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 */
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 */
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);
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
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
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++;
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
}
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. */
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)
{
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))
}
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)
insn = (*operand->insert) (insn, val, &errmsg);
if (errmsg)
- as_warn (errmsg);
+ as_warn ("%s", errmsg);
}
else
insn |= ((val & ((1 << operand->bits) - 1)) << operand->shift);
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;
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;
if (reloc == BFD_RELOC_UNUSED)
reloc = operand->default_reloc;
- assert (reloc_operand == NULL);
+ gas_assert (reloc_operand == NULL);
reloc_operand = operand;
reloc_exp = t;
}
}
/* 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);
- if (reloc_howto->bitsize != reloc_operand->bits)
+ = bfd_reloc_type_lookup (stdoutput,
+ (bfd_reloc_code_real_type) reloc);
+ if (reloc_operand == NULL
+ || reloc_howto->bitsize != reloc_operand->bits)
{
as_bad (_("invalid relocation for field"));
return;
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);
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++;
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
{
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++;
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];
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++;
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++;
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);
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++;
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++;
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++;
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++;
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
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);
}
/* 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)
{
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. */
\f
#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 current 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. */
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 */
\f
/* Assembler directives. */
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;
#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)
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 == ',')
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"));
}
#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 ();
}
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;
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;
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. */
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
{
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. */
/* 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++;
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
{
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;
}
cur_frame_data = NULL;
-
- *input_line_pointer = name_end;
}
+
+ (void) restore_line_pointer (name_end);
demand_empty_rest_of_line ();
}
}
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 ();
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;
}
static void
s_alpha_coff_wrapper (int which)
{
- static void (* const fns[]) PARAMS ((int)) = {
+ static void (* const fns[]) (int) = {
ecoff_directive_begin,
ecoff_directive_bend,
ecoff_directive_def,
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);
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)
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)
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 != ',')
{
}
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;
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));
#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;
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);
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 ();
}
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++ != ','
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++ != ',')
{
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 <entry_name>,{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++ != ',')
}
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
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. */
{
char *p;
expressionS exp;
- segment_info_type *seginfo = seg_info (alpha_link_section);
if (now_seg != alpha_link_section)
{
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 <symbol>.
+ 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 ();
}
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 <symbol>.
+ Create a code address relocation. */
+
static void
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 ();
}
}
else
{
- alpha_evax_proc.imask = val;
+ alpha_evax_proc->imask = val;
(void) get_absolute_expression ();
}
demand_empty_rest_of_line ();
}
else
{
- alpha_evax_proc.fmask = val;
+ alpha_evax_proc->fmask = val;
(void) get_absolute_expression ();
}
demand_empty_rest_of_line ();
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
}
/* Handle floating point allocation pseudo-ops. This is like the
- generic vresion, but it makes sure the current label, if any, is
+ generic version, but it makes sure the current label, if any, is
correctly aligned. */
static void
/* 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;
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 ();
}
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')
{
else
as_warn (_("Tried to .set unrecognized mode `%s'"), name);
- *input_line_pointer = ch;
+ (void) restore_line_pointer (ch);
demand_empty_rest_of_line ();
}
{
int align;
char fill, *pfill;
- long max_alignment = 15;
+ long max_alignment = 16;
align = get_absolute_expression ();
if (align > max_alignment)
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 ();
}
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)
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 ();
}
\f
{
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;
}
}
{"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. */
{"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'},
/* @@@ 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 (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;
}
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;
#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;
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
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. */
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);
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)
{
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);
/* 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)
{
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:
#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
}
#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);
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;
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
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:
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:
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;
{
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)
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;
}
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;