/* tc-vax.c - vax-specific -
- Copyright 1987, 1991, 1992, 1993, 1994, 1995, 1998, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
+ Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
bbsc e4
bbcc e5
Always, you complement 0th bit to reverse condition.
- Always, 1-byte opcde, longword-address, byte-address, 1-byte-displacement
+ Always, 1-byte opcode, longword-address, byte-address, 1-byte-displacement
2c. J<cond> where cond tests low-order memory bit
length of byte,word,long.
#define BB (1+-128)
#define WF (2+ 32767)
#define WB (2+-32768)
-/* Dont need LF, LB because they always reach. [They are coded as 0.] */
+/* Don't need LF, LB because they always reach. [They are coded as 0.] */
#define C(a,b) ENCODE_RELAX(a,b)
/* This macro has no side-effects. */
#undef WB
void float_cons (int);
-int flonum_gen2vax (char, FLONUM_TYPE *, LITTLENUM_TYPE *);
+int flonum_gen2vax (int, FLONUM_TYPE *, LITTLENUM_TYPE *);
const pseudo_typeS md_pseudo_table[] =
{
{
valueT value = * valueP;
- if (((fixP->fx_addsy == NULL && fixP->fx_subsy == NULL)
- && fixP->fx_r_type != BFD_RELOC_32_PLT_PCREL
- && fixP->fx_r_type != BFD_RELOC_32_GOT_PCREL)
- || fixP->fx_r_type == NO_RELOC)
- number_to_chars_littleendian (fixP->fx_where + fixP->fx_frag->fr_literal,
- value, fixP->fx_size);
+ if (fixP->fx_subsy != (symbolS *) NULL)
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
- if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
+ if (fixP->fx_addsy == NULL)
fixP->fx_done = 1;
+
+ if (fixP->fx_done)
+ number_to_chars_littleendian (fixP->fx_where + fixP->fx_frag->fr_literal,
+ value, fixP->fx_size);
+ else
+ /* Initialise the part of an instruction frag covered by the
+ relocation. (Many occurrences of frag_more followed by fix_new
+ lack any init of the frag.) Since VAX uses RELA relocs the
+ value we write into this field doesn't really matter. */
+ memset (fixP->fx_where + fixP->fx_frag->fr_literal, 0, fixP->fx_size);
}
/* Convert a number from VAX byte order (little endian)
int old_fr_fix;
old_fr_fix = fragP->fr_fix;
- p = fragP->fr_literal + old_fr_fix;
+ p = &fragP->fr_literal[0] + old_fr_fix;
#ifdef OBJ_ELF
/* If this is to an undefined symbol, then if it's an indirect
reference indicate that is can mutated into a GLOB_DAT or
|| S_IS_WEAK (fragP->fr_symbol)
|| S_IS_EXTERNAL (fragP->fr_symbol)))
{
- if (p[0] & 0x10)
- {
- if (flag_want_pic)
- as_fatal ("PIC reference to %s is indirect.\n",
- S_GET_NAME (fragP->fr_symbol));
- }
+ /* Indirect references cannot go through the GOT or PLT,
+ let's hope they'll become local in the final link. */
+ if ((ELF_ST_VISIBILITY (S_GET_OTHER (fragP->fr_symbol))
+ != STV_DEFAULT)
+ || (p[0] & 0x10))
+ reloc_type = BFD_RELOC_32_PCREL;
+ else if (((unsigned char *) fragP->fr_opcode)[0] == VAX_CALLS
+ || ((unsigned char *) fragP->fr_opcode)[0] == VAX_CALLG
+ || ((unsigned char *) fragP->fr_opcode)[0] == VAX_JSB
+ || ((unsigned char *) fragP->fr_opcode)[0] == VAX_JMP
+ || S_IS_FUNCTION (fragP->fr_symbol))
+ reloc_type = BFD_RELOC_32_PLT_PCREL;
else
- {
- if (((unsigned char *) fragP->fr_opcode)[0] == VAX_CALLS
- || ((unsigned char *) fragP->fr_opcode)[0] == VAX_CALLG
- || ((unsigned char *) fragP->fr_opcode)[0] == VAX_JSB
- || ((unsigned char *) fragP->fr_opcode)[0] == VAX_JMP
- || S_IS_FUNCTION (fragP->fr_symbol))
- reloc_type = BFD_RELOC_32_PLT_PCREL;
- else
- reloc_type = BFD_RELOC_32_GOT_PCREL;
- }
+ reloc_type = BFD_RELOC_32_GOT_PCREL;
}
#endif
switch (RELAX_STATE (fragP->fr_subtype))
know (fragP->fr_type == rs_machine_dependent);
where = fragP->fr_fix;
- addressP = fragP->fr_literal + where;
+ addressP = &fragP->fr_literal[0] + where;
opcodeP = fragP->fr_opcode;
symbolP = fragP->fr_symbol;
know (symbolP);
source file, and changed the makefile. */
/* Handle of the OPCODE hash table. */
-static struct hash_control *op_hash;
+static htab_t op_hash;
/* In: 1 character, from "bdfghloqpw" being the data-type of an operand
of a vax instruction.
ban these opcodes. They are mnemonics for "elastic" instructions
that are supposed to assemble into the fewest bytes needed to do a
branch, or to do a conditional branch, or whatever.
-
+
The opcode is in the usual place [low-order n*8 bits]. This means
that if you mask off the bucky bits, the usual rules apply about
how long the opcode is.
-
+
All VAX branch displacements come at the end of the instruction.
For simple branches (1-byte opcode + 1-byte displacement) the last
operand is coded 'b?' where the "data type" '?' is a clue that we
and branch around a jump. This is by far the most common case.
That is why the VIT_OPCODE_SYNTHETIC bit is set: it says this is
a 0-byte op-code followed by 2 or more bytes of operand address.
-
+
If the op-code has VIT_OPCODE_SPECIAL set, then we have a more unusual
case.
-
+
For JBSB & JBR the treatment is the similar, except (1) we have a 'bw'
option before (2) we can directly JSB/JMP because there is no condition.
These operands have 'b-' as their access/data type.
-
+
That leaves a bunch of random opcodes: JACBx, JxOBxxx. In these
cases, we do the same idea. JACBxxx are all marked with a 'b!'
JAOBxxx & JSOBxxx are marked with a 'b:'. */
{"jbcs", {"rlvbb?", 0x800000e3}},
{"jbsc", {"rlvbb?", 0x800000e4}},
{"jbcc", {"rlvbb?", 0x800000e5}},
+ {"jbssi", {"rlvbb?", 0x800000e6}},
+ {"jbcci", {"rlvbb?", 0x800000e7}},
{"jlbs", {"rlb?", 0x800000e8}},
{"jlbc", {"rlb?", 0x800000e9}},
instruction table.
You must nominate metacharacters for eg DEC's "#", "@", "^". */
-static const char *
+static void
vip_begin (int synthetic_too, /* 1 means include jXXX op-codes. */
const char *immediate,
const char *indirect,
const char *displen)
{
const struct vot *vP; /* scan votstrs */
- const char *retval = 0; /* error text */
- op_hash = hash_new ();
+ op_hash = str_htab_create ();
- for (vP = votstrs; *vP->vot_name && !retval; vP++)
- retval = hash_insert (op_hash, vP->vot_name, (PTR) &vP->vot_detail);
+ for (vP = votstrs; *vP->vot_name; vP++)
+ str_hash_insert (op_hash, vP->vot_name, (void *) &vP->vot_detail);
if (synthetic_too)
- for (vP = synthetic_votstrs; *vP->vot_name && !retval; vP++)
- retval = hash_insert (op_hash, vP->vot_name, (PTR) &vP->vot_detail);
+ for (vP = synthetic_votstrs; *vP->vot_name; vP++)
+ str_hash_insert (op_hash, vP->vot_name, (void *) &vP->vot_detail);
#ifndef CONST_TABLE
vip_op_defaults (immediate, indirect, displen);
#endif
-
- return retval;
}
/* Take 3 char.s, the last of which may be `\0` (non-existent)
and return the VAX register number that they represent.
-
+
Return -1 if they don't form a register name. Good names return
a number from 0:15 inclusive.
-
+
Case is not important in a name.
-
+
Register names understood are:
-
+
R0
R1
R2
For speed, expect a string of whitespace to be reduced to a single ' '.
This is the case for GNU AS, and is easy for other DEC-compatible
assemblers.
-
+
Knowledge about DEC VAX assembler operand notation lives here.
This doesn't even know what a register name is, except it believes
all register names are 2 or 3 characters, and lets vax_reg_parse() say
what number each name represents.
It does, however, know that PC, SP etc are special registers so it can
detect addressing modes that are silly for those registers.
-
+
Where possible, it delivers 1 fatal or 1 warning message if the operand
is suspect. Exactly what we test for is still evolving.
---
Arg block.
-
+
There were a number of 'mismatched argument type' bugs to vip_op.
The most general solution is to typedef each (of many) arguments.
We used instead a typedef'd argument block. This is less modular
on most engines, and seems to keep programmers happy. It will have
to be done properly if we ever want to use vip_op as a general-purpose
module (it was designed to be).
-
+
G^
Doesn't support DEC "G^" format operands. These always take 5 bytes
If there is some other use for "G^", feel free to code it in!
speed
-
+
If I nested if()s more, I could avoid testing (*err) which would save
time, space and page faults. I didn't nest all those if()s for clarity
and because I think the mode testing can be re-arranged 1st to test the
- commoner constructs 1st. Does anybody have statistics on this?
-
+ commoner constructs 1st. Does anybody have statistics on this?
+
error messages
-
+
In future, we should be able to 'compose' error messages in a scratch area
and give the user MUCH more informative error messages. Although this takes
a little more code at run-time, it will make this module much more self-
the Un*x characters "$`*", that most users will expect from this AS.
----
-
+
The input is a string, ending with '\0'.
-
+
We also require a 'hint' of what kind of operand is expected: so
we can remind caller not to write into literals for instance.
-
+
The output is a skeletal instruction.
-
+
The algorithm has two parts.
1. extract the syntactic features (parse off all the @^#-()+[] mode crud);
2. express the @^#-()+[] as some parameters suited to further analysis.
-
+
2nd step is where we detect the googles of possible invalid combinations
a human (or compiler) might write. Note that if we do a half-way
decent assembler, we don't know how long to make (eg) displacement
- error text(s) why we couldn't understand the operand
----
-
+
To decode output of this, test errtxt. If errtxt[0] == '\0', then
we had no errors that prevented parsing. Also, if we ever report
an internal bug, errtxt[0] is set non-zero. So one test tells you
if the other outputs are to be taken seriously.
----
-
+
Dec defines the semantics of address modes (and values)
by a two-letter code, explained here.
-
+
letter 1: access type
-
+
a address calculation - no data access, registers forbidden
b branch displacement
m read - let go of bus - write back "modify"
v bit field address: like 'a' but registers are OK
w write
space no operator (eg ".long foo") [our convention]
-
+
letter 2: data type (i.e. width, alignment)
-
+
b byte
d double precision floating point (D format)
f single precision floating point (F format)
? simple synthetic branch operand
- unconditional synthetic JSB/JSR operand
! complex synthetic branch operand
-
+
The '-?!' letter 2's are not for external consumption. They are used
for various assemblers. Generally, all unknown widths are assumed 0.
We don't limit your choice of width character.
-
+
DEC operands are hard work to parse. For example, '@' as the first
character means indirect (deferred) mode but elsewhere it is a shift
operator.
We try hard not to parse anything that MIGHT be part of the expression
buried in that syntax. For example if we see @...(Rn) we don't check
for '-' before the '(' because mode @-(Rn) does not exist.
-
+
After parsing we have:
-
+
at 1 if leading '@' (or Un*x '*')
len takes one value from " bilsw". eg B^ -> 'b'.
hash 1 if leading '#' (or Un*x '$')
paren 1 if () are around register
reg major register number 0:15 -1 means absent
ndx index register number 0:15 -1 means absent
-
+
Again, I dare not explain it: just trace ALL the code!
Summary of vip_op outputs.
get the types wrong below, we lose at compile time rather than at
lint or run time. */
char access_mode; /* vop_access. */
- char width; /* vop_width. */
access_mode = vopP->vop_access;
- width = vopP->vop_width;
/* None of our code bugs (yet), no user text errors, no warnings
even. */
err = wrn = 0;
/* p points to what may be the beginning of an expression.
We have peeled off the front all that is peelable.
We know at, len, hash.
-
+
Lets point q at the end of the text and parse that (backwards). */
for (q = p; *q; q++)
We will deliver a 4-bit reg, and a 4-bit mode. */
/* Case of branch operand. Different. No L^B^W^I^S^ allowed for instance.
-
+
in: at ?
len ?
hash ?
paren ?
reg ?
ndx ?
-
+
out: mode 0
reg -1
len ' '
/* Since nobody seems to use it: comment this 'feature'(?) out for now. */
#ifdef NEVER
/* Case of stand-alone operand. e.g. ".long foo"
-
+
in: at ?
len ?
hash ?
paren ?
reg ?
ndx ?
-
+
out: mode 0
reg -1
len ' '
#endif
/* Case of S^#.
-
+
in: at 0
len 's' definition
hash 1 demand
paren 0 by "()" scan logic because "S^" seen
reg -1 or nn by mistake
ndx -1
-
+
out: mode 0
reg -1
len 's'
err = _("S^# may only read-access");
}
}
-
+
/* Case of -(Rn), which is weird case.
-
+
in: at 0
len '
hash 0
paren 1 by definition
reg present by definition
ndx optional
-
+
out: mode 7
reg present
len ' '
}
/* Case of (Rn)+, which is slightly different.
-
+
in: at
len ' '
hash 0
paren 1 by definition
reg present by definition
ndx optional
-
+
out: mode 8+@
reg present
len ' '
}
/* Case of #, without S^.
-
+
in: at
len ' ' or 'i'
hash 1 by definition
paren 0
reg absent
ndx optional
-
+
out: mode 8+@
reg PC
len ' ' or 'i'
/* Case of Rn. We separate this one because it has a few special
errors the remaining modes lack.
-
+
in: at optional
len ' '
hash 0 by program logic
paren 0 by definition
reg present by definition
ndx optional
-
+
out: mode 5+@
reg present
len ' ' enforce no length
paren == 1 OR reg==-1 */
/* Rest of cases fit into one bunch.
-
+
in: at optional
len ' ' or 'b' or 'w' or 'l'
hash 0 by program logic
paren optional
reg optional
ndx optional
-
+
out: mode 10 + @ + len
reg optional
len ' ' or 'b' or 'w' or 'l'
{
case 'l':
mode += 2;
+ /* Fall through. */
case 'w':
mode += 2;
+ /* Fall through. */
case ' ': /* Assumed B^ until our caller changes it. */
case 'b':
break;
knowledge of how you parse (or evaluate) your expressions.
We do however strip off and decode addressing modes and operation
mnemonic.
-
+
The exploded instruction is returned to a struct vit of your choice.
#include "vax-inst.h" to know what a struct vit is.
-
+
This function's value is a string. If it is not "" then an internal
logic error was found: read this code to assign meaning to the string.
No argument string should generate such an error string:
it means a bug in our code, not in the user's text.
-
+
You MUST have called vip_begin() once before using this function. */
static void
if (*instring == ' ')
++instring;
-
+
/* MUST end in end-of-string or exactly 1 space. */
for (p = instring; *p && *p != ' '; p++)
;
/* Here with instring pointing to what better be an op-name, and p
pointing to character just past that.
We trust instring points to an op-name, with no whitespace. */
- vwP = (struct vot_wot *) hash_find (op_hash, instring);
+ vwP = (struct vot_wot *) str_hash_find (op_hash, instring);
/* Restore char after op-code. */
*p = c;
if (vwP == 0)
printf ("enter displen symbols eg enter ^ ");
gets (my_displen);
- if (p = vip_begin (mysynth, my_immediate, my_indirect, my_displen))
- error ("vip_begin=%s", p);
+ vip_begin (mysynth, my_immediate, my_indirect, my_displen)
printf ("An empty input line will quit you from the vax instruction parser\n");
for (;;)
We declare arrays non-local in case some of our tiny-minded machines
default to small stacks. Also, helps with some debuggers. */
-#include <stdio.h>
-
char answer[100]; /* Human types into here. */
char *p; /* */
char *myerr;
default:
my_operand_length = 2;
- printf ("I dn't understand access width %c\n", mywidth);
+ printf ("I don't understand access width %c\n", mywidth);
break;
}
printf ("VAX assembler instruction operand: ");
size_t md_longopts_size = sizeof (md_longopts);
int
-md_parse_option (int c, char *arg)
+md_parse_option (int c, const char *arg)
{
switch (c)
{
if (fixp->fx_tcbit)
abort ();
- if (fixp->fx_r_type != BFD_RELOC_NONE)
+ if (fixp->fx_r_type != NO_RELOC)
{
code = fixp->fx_r_type;
#undef F
#undef MAP
- reloc = xmalloc (sizeof (arelent));
- 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;
#ifndef OBJ_ELF
#endif
reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
- assert (reloc->howto != 0);
+ gas_assert (reloc->howto != 0);
return reloc;
}
if (need_pass_2 || goofed)
return;
+ dwarf2_emit_insn (0);
/* Emit op-code. */
/* Remember where it is, in case we want to modify the op-code later. */
opcode_low_byteP = frag_more (v.vit_opcode_nbytes);
|| operandP->vop_access == 'a')
{
if (operandP->vop_access == 'v')
- as_warn (_("Invalid operand: immediate value used as base address."));
+ as_warn (_("Invalid operand: immediate value used as base address."));
else
- as_warn (_("Invalid operand: immediate value used as address."));
+ as_warn (_("Invalid operand: immediate value used as address."));
/* gcc 2.6.3 is known to generate these in at least
one case. */
}
if (flag_want_pic && operandP->vop_mode == 8
&& this_add_symbol != NULL)
{
- as_warn (_("Symbol used as immediate operand in PIC mode."));
+ as_warn (_("Symbol %s used as immediate operand in PIC mode."),
+ S_GET_NAME (this_add_symbol));
}
#endif
p[0] = (operandP->vop_mode << 4) | 0xF;
min (sizeof (valueT),
(size_t) nbytes));
if ((size_t) nbytes > sizeof (valueT))
- memset (p + 5, '\0', nbytes - sizeof (valueT));
+ memset (p + 1 + sizeof (valueT),
+ '\0', nbytes - sizeof (valueT));
}
else
{
void
md_begin (void)
{
- const char *errtxt;
FLONUM_TYPE *fP;
int i;
- if ((errtxt = vip_begin (1, "$", "*", "`")) != 0)
- as_fatal (_("VIP_BEGIN error:%s"), errtxt);
+ vip_begin (1, "$", "*", "`");
for (i = 0, fP = float_operand;
fP < float_operand + VIT_MAX_OPERANDS;
fP->high = &big_operand_bits[i][SIZE_OF_LARGE_NUMBER - 1];
}
}
+
+bfd_reloc_code_real_type
+vax_cons (expressionS *exp, int size)
+{
+ char *save;
+ const char *vax_cons_special_reloc;
+
+ SKIP_WHITESPACE ();
+ vax_cons_special_reloc = NULL;
+ save = input_line_pointer;
+ if (input_line_pointer[0] == '%')
+ {
+ if (strncmp (input_line_pointer + 1, "pcrel", 5) == 0)
+ {
+ input_line_pointer += 6;
+ vax_cons_special_reloc = "pcrel";
+ }
+ if (vax_cons_special_reloc)
+ {
+ int bad = 0;
+
+ switch (size)
+ {
+ case 1:
+ if (*input_line_pointer != '8')
+ bad = 1;
+ input_line_pointer--;
+ break;
+ case 2:
+ if (input_line_pointer[0] != '1' || input_line_pointer[1] != '6')
+ bad = 1;
+ break;
+ case 4:
+ if (input_line_pointer[0] != '3' || input_line_pointer[1] != '2')
+ bad = 1;
+ break;
+ default:
+ bad = 1;
+ break;
+ }
+
+ if (bad)
+ {
+ as_bad (_("Illegal operands: Only %%r_%s%d allowed in %d-byte data fields"),
+ vax_cons_special_reloc, size * 8, size);
+ }
+ else
+ {
+ input_line_pointer += 2;
+ if (*input_line_pointer != '(')
+ {
+ as_bad (_("Illegal operands: %%r_%s%d requires arguments in ()"),
+ vax_cons_special_reloc, size * 8);
+ bad = 1;
+ }
+ }
+
+ if (bad)
+ {
+ input_line_pointer = save;
+ vax_cons_special_reloc = NULL;
+ }
+ else
+ {
+ int c;
+ char *end = ++input_line_pointer;
+ int npar = 0;
+
+ while (! is_end_of_line[(c = *end)])
+ {
+ if (c == '(')
+ npar++;
+ else if (c == ')')
+ {
+ if (!npar)
+ break;
+ npar--;
+ }
+ end++;
+ }
+
+ if (c != ')')
+ as_bad (_("Illegal operands: %%r_%s%d requires arguments in ()"),
+ vax_cons_special_reloc, size * 8);
+ else
+ {
+ *end = '\0';
+ expression (exp);
+ *end = c;
+ if (input_line_pointer != end)
+ {
+ as_bad (_("Illegal operands: %%r_%s%d requires arguments in ()"),
+ vax_cons_special_reloc, size * 8);
+ }
+ else
+ {
+ input_line_pointer++;
+ SKIP_WHITESPACE ();
+ c = *input_line_pointer;
+ if (! is_end_of_line[c] && c != ',')
+ as_bad (_("Illegal operands: garbage after %%r_%s%d()"),
+ vax_cons_special_reloc, size * 8);
+ }
+ }
+ }
+ }
+ }
+ if (vax_cons_special_reloc == NULL)
+ expression (exp);
+ else
+ switch (size)
+ {
+ case 1: return BFD_RELOC_8_PCREL;
+ case 2: return BFD_RELOC_16_PCREL;
+ case 4: return BFD_RELOC_32_PCREL;
+ }
+ return NO_RELOC;
+}
+
+/* This is called by emit_expr via TC_CONS_FIX_NEW when creating a
+ reloc for a cons. */
+
+void
+vax_cons_fix_new (fragS *frag, int where, unsigned int nbytes, expressionS *exp,
+ bfd_reloc_code_real_type r)
+{
+ if (r == NO_RELOC)
+ r = (nbytes == 1 ? BFD_RELOC_8
+ : nbytes == 2 ? BFD_RELOC_16
+ : BFD_RELOC_32);
+
+ fix_new_exp (frag, where, (int) nbytes, exp, 0, r);
+}
+
+const char *
+md_atof (int type, char * litP, int * sizeP)
+{
+ return vax_md_atof (type, litP, sizeP);
+}