#include "as.h"
#include "vax-inst.h"
#include "obstack.h"
#include "subsegs.h"
#ifdef OBJ_ELF
#include "elf/vax.h"
#endif
#if defined (OBJ_AOUT) && !defined (BFD_ASSEMBLER) && defined (TE_NetBSD)
#include <netinet/in.h>
#endif
const char comment_chars[] = "#";
const char line_comment_chars[] = "#";
const char line_separator_chars[] = ";";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "dDfFgGhH";
static expressionS exp_of_operand[VIT_MAX_OPERANDS];
static segT seg_of_operand[VIT_MAX_OPERANDS];
static struct vit v;
LITTLENUM_TYPE big_operand_bits[VIT_MAX_OPERANDS][SIZE_OF_LARGE_NUMBER];
FLONUM_TYPE float_operand[VIT_MAX_OPERANDS];
#ifdef OBJ_ELF
#define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_"
#define PROCEDURE_LINKAGE_TABLE_NAME "_PROCEDURE_LINKAGE_TABLE_"
symbolS *GOT_symbol;
symbolS *PLT_symbol;
#endif
int flag_hash_long_names;
int flag_one;
int flag_show_after_trunc;
int flag_no_hash_mixed_case;
#ifdef OBJ_ELF
int flag_want_pic;
#endif
#define BF (1+ 127)
#define BB (1+-128)
#define WF (2+ 32767)
#define WB (2+-32768)
#define C(a,b) ENCODE_RELAX(a,b)
#define ENCODE_RELAX(what,length) (((what) << 2) + (length))
#define RELAX_STATE(s) ((s) >> 2)
#define RELAX_LENGTH(s) ((s) & 3)
const relax_typeS md_relax_table[] =
{
{1, 1, 0, 0},
{1, 1, 0, 0},
{1, 1, 0, 0},
{1, 1, 0, 0},
{BF + 1, BB + 1, 2, C (1, 1)},
{WF + 1, WB + 1, 3, C (1, 2)},
{0, 0, 5, 0},
{1, 1, 0, 0},
{BF, BB, 1, C (2, 1)},
{WF + 2, WB + 2, 4, C (2, 2)},
{0, 0, 7, 0},
{1, 1, 0, 0},
{BF, BB, 1, C (3, 1)},
{WF, WB, 2, C (3, 2)},
{0, 0, 5, 0},
{1, 1, 0, 0},
{1, 1, 0, 0},
{WF, WB, 2, C (4, 2)},
{0, 0, 10, 0},
{1, 1, 0, 0},
{BF, BB, 1, C (5, 1)},
{WF + 4, WB + 4, 6, C (5, 2)},
{0, 0, 9, 0},
{1, 1, 0, 0},
};
#undef C
#undef BF
#undef BB
#undef WF
#undef WB
void float_cons PARAMS ((int));
const pseudo_typeS md_pseudo_table[] =
{
{"dfloat", float_cons, 'd'},
{"ffloat", float_cons, 'f'},
{"gfloat", float_cons, 'g'},
{"hfloat", float_cons, 'h'},
{NULL, NULL, 0},
};
#define STATE_PC_RELATIVE (1)
#define STATE_CONDITIONAL_BRANCH (2)
#define STATE_ALWAYS_BRANCH (3)
#define STATE_COMPLEX_BRANCH (4)
#define STATE_COMPLEX_HOP (5)
#define STATE_BYTE (0)
#define STATE_WORD (1)
#define STATE_LONG (2)
#define STATE_UNDF (3)
#define min(a, b) ((a) < (b) ? (a) : (b))
int flonum_gen2vax PARAMS ((char format_letter, FLONUM_TYPE * f,
LITTLENUM_TYPE * words));
static const char *vip_begin PARAMS ((int, const char *, const char *,
const char *));
static void vip_op_1 PARAMS ((int, const char *));
static void vip_op_defaults PARAMS ((const char *, const char *, const char *));
static void vip_op PARAMS ((char *, struct vop *));
static void vip PARAMS ((struct vit *, char *));
static int vax_reg_parse PARAMS ((char, char, char, char));
void
md_begin ()
{
const char *errtxt;
FLONUM_TYPE *fP;
int i;
if ((errtxt = vip_begin (1, "$", "*", "`")) != 0)
{
as_fatal (_("VIP_BEGIN error:%s"), errtxt);
}
for (i = 0, fP = float_operand;
fP < float_operand + VIT_MAX_OPERANDS;
i++, fP++)
{
fP->low = &big_operand_bits[i][0];
fP->high = &big_operand_bits[i][SIZE_OF_LARGE_NUMBER - 1];
}
}
void
md_number_to_chars (con, value, nbytes)
char con[];
valueT value;
int nbytes;
{
number_to_chars_littleendian (con, value, nbytes);
}
void
md_apply_fix3 (fixP, valueP, seg)
fixS *fixP;
valueT *valueP;
segT seg ATTRIBUTE_UNUSED;
{
valueT value = * valueP;
#ifdef BFD_ASSEMBLER
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)
#endif
number_to_chars_littleendian (fixP->fx_where + fixP->fx_frag->fr_literal,
value, fixP->fx_size);
if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
fixP->fx_done = 1;
}
long
md_chars_to_number (con, nbytes)
unsigned char con[];
int nbytes;
{
long retval;
for (retval = 0, con += nbytes - 1; nbytes--; con--)
{
retval <<= BITS_PER_CHAR;
retval |= *con;
}
return retval;
}
void
md_assemble (instruction_string)
char *instruction_string;
{
int is_undefined;
int is_absolute;
int length_code;
char *p;
struct vop *operandP;
char *save_input_line_pointer;
char c_save;
int goofed;
struct vop *end_operandP;
expressionS *expP;
segT *segP;
segT to_seg;
valueT this_add_number;
symbolS *this_add_symbol;
long opcode_as_number;
char *opcode_as_chars;
char *opcode_low_byteP;
int length;
int at;
int nbytes;
FLONUM_TYPE *floatP;
LITTLENUM_TYPE literal_float[8];
vip (&v, instruction_string);
if ((goofed = (*v.vit_error)) != 0)
{
as_fatal (_("Ignoring statement due to \"%s\""), v.vit_error);
}
save_input_line_pointer = input_line_pointer;
for (operandP = v.vit_operand,
expP = exp_of_operand,
segP = seg_of_operand,
floatP = float_operand,
end_operandP = v.vit_operand + v.vit_operands;
operandP < end_operandP;
operandP++, expP++, segP++, floatP++)
{
if (operandP->vop_error)
{
as_fatal (_("Aborting because statement has \"%s\""), operandP->vop_error);
goofed = 1;
}
else
{
int can_be_short = 0;
input_line_pointer = operandP->vop_expr_begin;
c_save = operandP->vop_expr_end[1];
operandP->vop_expr_end[1] = '\0';
*segP = expression (expP);
switch (expP->X_op)
{
case O_absent:
expP->X_op = O_constant;
expP->X_add_number = 0;
expP->X_add_symbol = NULL;
expP->X_op_symbol = NULL;
break;
case O_symbol:
case O_constant:
break;
default:
need_pass_2 = 1;
as_fatal (_("Can't relocate expression"));
break;
case O_big:
if (expP->X_add_number > 0)
{
bignum_copy (generic_bignum, expP->X_add_number,
floatP->low, SIZE_OF_LARGE_NUMBER);
}
else
{
know (expP->X_add_number < 0);
flonum_copy (&generic_floating_point_number,
floatP);
if (strchr ("s i", operandP->vop_short))
{
flonum_gen2vax (-expP->X_add_number, floatP, literal_float);
switch (-expP->X_add_number)
{
case 'f':
can_be_short =
(literal_float[0] & 0xFC0F) == 0x4000
&& literal_float[1] == 0;
break;
case 'd':
can_be_short =
(literal_float[0] & 0xFC0F) == 0x4000
&& literal_float[1] == 0
&& literal_float[2] == 0
&& literal_float[3] == 0;
break;
case 'g':
can_be_short =
(literal_float[0] & 0xFF81) == 0x4000
&& literal_float[1] == 0
&& literal_float[2] == 0
&& literal_float[3] == 0;
break;
case 'h':
can_be_short = ((literal_float[0] & 0xFFF8) == 0x4000
&& (literal_float[1] & 0xE000) == 0
&& literal_float[2] == 0
&& literal_float[3] == 0
&& literal_float[4] == 0
&& literal_float[5] == 0
&& literal_float[6] == 0
&& literal_float[7] == 0);
break;
default:
BAD_CASE (-expP->X_add_number);
break;
}
}
}
if (operandP->vop_short == 's'
|| operandP->vop_short == 'i'
|| (operandP->vop_short == ' '
&& operandP->vop_reg == 0xF
&& (operandP->vop_mode & 0xE) == 0x8))
{
if (operandP->vop_short == ' ')
{
if (expP->X_add_number > 0)
{
operandP->vop_short = 'i';
operandP->vop_mode = 8;
operandP->vop_reg = 0xF;
}
else
{
if (can_be_short)
{
operandP->vop_short = 's';
operandP->vop_mode = 0;
operandP->vop_ndx = -1;
operandP->vop_reg = -1;
expP->X_op = O_constant;
}
else
{
operandP->vop_short = 'i';
operandP->vop_mode = 8;
operandP->vop_reg = 0xF;
}
}
}
if (operandP->vop_short == 's')
{
if (expP->X_add_number > 0)
{
as_warn (_("Bignum not permitted in short literal. Immediate mode assumed."));
operandP->vop_short = 'i';
operandP->vop_mode = 8;
operandP->vop_reg = 0xF;
}
else
{
if (!can_be_short)
{
as_warn (_("Can't do flonum short literal: immediate mode used."));
operandP->vop_short = 'i';
operandP->vop_mode = 8;
operandP->vop_reg = 0xF;
}
else
{
int temp = 0;
switch (-expP->X_add_number)
{
case 'f':
case 'd':
temp = literal_float[0] >> 4;
break;
case 'g':
temp = literal_float[0] >> 1;
break;
case 'h':
temp = ((literal_float[0] << 3) & 070)
| ((literal_float[1] >> 13) & 07);
break;
default:
BAD_CASE (-expP->X_add_number);
break;
}
floatP->low[0] = temp & 077;
floatP->low[1] = 0;
}
}
}
else
{
if (expP->X_add_number < 0)
{
memcpy (floatP->low, literal_float, sizeof (literal_float));
}
}
}
else
{
as_warn (_("A bignum/flonum may not be a displacement: 0x%lx used"),
(expP->X_add_number = 0x80000000L));
}
expP->X_add_number = floatP->low[0]
| ((LITTLENUM_MASK & (floatP->low[1])) << LITTLENUM_NUMBER_OF_BITS);
break;
}
if (input_line_pointer != operandP->vop_expr_end + 1)
{
as_fatal ("Junk at end of expression \"%s\"", input_line_pointer);
goofed = 1;
}
operandP->vop_expr_end[1] = c_save;
}
}
input_line_pointer = save_input_line_pointer;
if (need_pass_2 || goofed)
{
return;
}
opcode_low_byteP = frag_more (v.vit_opcode_nbytes);
memcpy (opcode_low_byteP, v.vit_opcode, v.vit_opcode_nbytes);
opcode_as_chars = v.vit_opcode;
opcode_as_number = md_chars_to_number ((unsigned char *) opcode_as_chars, 4);
for (operandP = v.vit_operand,
expP = exp_of_operand,
segP = seg_of_operand,
floatP = float_operand,
end_operandP = v.vit_operand + v.vit_operands;
operandP < end_operandP;
operandP++,
floatP++,
segP++,
expP++)
{
if (operandP->vop_ndx >= 0)
{
FRAG_APPEND_1_CHAR (0x40 + operandP->vop_ndx);
}
this_add_number = expP->X_add_number;
this_add_symbol = expP->X_add_symbol;
to_seg = *segP;
#ifdef BFD_ASSEMBLER
is_undefined = (to_seg == undefined_section);
is_absolute = (to_seg == absolute_section);
#else
is_undefined = (to_seg == SEG_UNKNOWN);
is_absolute = (to_seg == SEG_ABSOLUTE);
#endif
at = operandP->vop_mode & 1;
length = (operandP->vop_short == 'b'
? 1 : (operandP->vop_short == 'w'
? 2 : (operandP->vop_short == 'l'
? 4 : 0)));
nbytes = operandP->vop_nbytes;
if (operandP->vop_access == 'b')
{
if (to_seg == now_seg || is_undefined)
{
if (nbytes)
{
p = frag_more (nbytes);
fix_new (frag_now, p - frag_now->fr_literal, nbytes,
this_add_symbol, this_add_number, 1, NO_RELOC);
}
else
{
length_code = is_undefined ? STATE_UNDF : STATE_BYTE;
if (opcode_as_number & VIT_OPCODE_SPECIAL)
{
if (operandP->vop_width == VAX_WIDTH_UNCONDITIONAL_JUMP)
{
frag_var (rs_machine_dependent, 5, 1,
ENCODE_RELAX (STATE_ALWAYS_BRANCH, length_code),
this_add_symbol, this_add_number,
opcode_low_byteP);
}
else
{
if (operandP->vop_width == VAX_WIDTH_WORD_JUMP)
{
length_code = STATE_WORD;
frag_var (rs_machine_dependent, 10, 2,
ENCODE_RELAX (STATE_COMPLEX_BRANCH, length_code),
this_add_symbol, this_add_number,
opcode_low_byteP);
}
else
{
know (operandP->vop_width == VAX_WIDTH_BYTE_JUMP);
frag_var (rs_machine_dependent, 9, 1,
ENCODE_RELAX (STATE_COMPLEX_HOP, length_code),
this_add_symbol, this_add_number,
opcode_low_byteP);
}
}
}
else
{
know (operandP->vop_width == VAX_WIDTH_CONDITIONAL_JUMP);
frag_var (rs_machine_dependent, 7, 1,
ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, length_code),
this_add_symbol, this_add_number,
opcode_low_byteP);
}
}
}
else
{
if (is_absolute)
{
if (nbytes)
{
know (!(opcode_as_number & VIT_OPCODE_SYNTHETIC));
p = frag_more (nbytes);
fix_new (frag_now, p - frag_now->fr_literal, nbytes,
#ifdef BFD_ASSEMBLER
section_symbol (absolute_section),
#else
&abs_symbol,
#endif
this_add_number, 1, NO_RELOC);
}
else
{
know (opcode_as_number & VIT_OPCODE_SYNTHETIC);
if (opcode_as_number & VIT_OPCODE_SPECIAL)
{
if (operandP->vop_width == VAX_WIDTH_UNCONDITIONAL_JUMP)
{
*opcode_low_byteP = opcode_as_chars[0] + VAX_WIDEN_LONG;
know (opcode_as_chars[1] == 0);
p = frag_more (5);
p[0] = VAX_ABSOLUTE_MODE;
md_number_to_chars (p + 1, this_add_number, 4);
}
else
{
if (operandP->vop_width == VAX_WIDTH_WORD_JUMP)
{
p = frag_more (10);
p[0] = 2;
p[1] = 0;
p[2] = VAX_BRB;
p[3] = 6;
p[4] = VAX_JMP;
p[5] = VAX_ABSOLUTE_MODE;
md_number_to_chars (p + 6, this_add_number, 4);
}
else
{
know (operandP->vop_width == VAX_WIDTH_BYTE_JUMP);
p = frag_more (9);
p[0] = 2;
p[1] = VAX_BRB;
p[2] = 6;
p[3] = VAX_JMP;
p[4] = VAX_ABSOLUTE_MODE;
md_number_to_chars (p + 5, this_add_number, 4);
}
}
}
else
{
*opcode_low_byteP ^= 1;
p = frag_more (7);
p[0] = 6;
p[1] = VAX_JMP;
p[2] = VAX_ABSOLUTE_MODE;
md_number_to_chars (p + 3, this_add_number, 4);
}
}
}
else
{
if (nbytes > 0)
{
know (!(opcode_as_number & VIT_OPCODE_SYNTHETIC));
p = frag_more (nbytes);
fix_new (frag_now, p - frag_now->fr_literal, nbytes,
#ifdef BFD_ASSEMBLER
section_symbol (absolute_section),
#else
&abs_symbol,
#endif
this_add_number, 1, NO_RELOC);
}
else
{
know (opcode_as_number & VIT_OPCODE_SYNTHETIC);
if (opcode_as_number & VIT_OPCODE_SPECIAL)
{
if (operandP->vop_width == VAX_WIDTH_UNCONDITIONAL_JUMP)
{
know (opcode_as_chars[1] == 0);
*opcode_low_byteP = opcode_as_chars[0] + VAX_WIDEN_LONG;
p = frag_more (5);
p[0] = VAX_PC_RELATIVE_MODE;
fix_new (frag_now,
p + 1 - frag_now->fr_literal, 4,
this_add_symbol,
this_add_number, 1, NO_RELOC);
}
else
{
if (operandP->vop_width == VAX_WIDTH_WORD_JUMP)
{
p = frag_more (10);
p[0] = 0;
p[1] = 2;
p[2] = VAX_BRB;
p[3] = 6;
p[4] = VAX_JMP;
p[5] = VAX_PC_RELATIVE_MODE;
fix_new (frag_now,
p + 6 - frag_now->fr_literal, 4,
this_add_symbol,
this_add_number, 1, NO_RELOC);
}
else
{
know (operandP->vop_width == VAX_WIDTH_BYTE_JUMP);
p = frag_more (10);
p[0] = 2;
p[1] = VAX_BRB;
p[2] = 6;
p[3] = VAX_JMP;
p[4] = VAX_PC_RELATIVE_MODE;
fix_new (frag_now,
p + 5 - frag_now->fr_literal,
4, this_add_symbol,
this_add_number, 1, NO_RELOC);
}
}
}
else
{
know (operandP->vop_width == VAX_WIDTH_CONDITIONAL_JUMP);
*opcode_low_byteP ^= 1;
p = frag_more (7);
p[0] = 6;
p[1] = VAX_JMP;
p[2] = VAX_PC_RELATIVE_MODE;
fix_new (frag_now, p + 3 - frag_now->fr_literal,
4, this_add_symbol,
this_add_number, 1, NO_RELOC);
}
}
}
}
}
else
{
know (operandP->vop_access != 'b');
know (operandP->vop_access != ' ');
know (operandP->vop_access == 'a'
|| operandP->vop_access == 'm'
|| operandP->vop_access == 'r'
|| operandP->vop_access == 'v'
|| operandP->vop_access == 'w');
if (operandP->vop_short == 's')
{
if (is_absolute)
{
if (this_add_number >= 64)
{
as_warn (_("Short literal overflow(%ld.), immediate mode assumed."),
(long) this_add_number);
operandP->vop_short = 'i';
operandP->vop_mode = 8;
operandP->vop_reg = 0xF;
}
}
else
{
as_warn (_("Forced short literal to immediate mode. now_seg=%s to_seg=%s"),
segment_name (now_seg), segment_name (to_seg));
operandP->vop_short = 'i';
operandP->vop_mode = 8;
operandP->vop_reg = 0xF;
}
}
if (operandP->vop_reg >= 0 && (operandP->vop_mode < 8
|| (operandP->vop_reg != 0xF && operandP->vop_mode < 10)))
{
know (operandP->vop_mode > 3);
FRAG_APPEND_1_CHAR (operandP->vop_mode << 4 | operandP->vop_reg);
}
else
{
if (operandP->vop_reg == -1 && operandP->vop_short != 's')
{
if (to_seg == now_seg)
{
if (length == 0)
{
know (operandP->vop_short == ' ');
length_code = STATE_BYTE;
#ifdef OBJ_ELF
if (S_IS_EXTERNAL (this_add_symbol)
|| S_IS_WEAK (this_add_symbol))
length_code = STATE_UNDF;
#endif
p = frag_var (rs_machine_dependent, 10, 2,
ENCODE_RELAX (STATE_PC_RELATIVE, length_code),
this_add_symbol, this_add_number,
opcode_low_byteP);
know (operandP->vop_mode == 10 + at);
*p = at << 4;
}
else
{
know (length);
know (operandP->vop_short != ' ');
p = frag_more (length + 1);
p[0] = 0xF | ((at + "?\12\14?\16"[length]) << 4);
fix_new (frag_now, p + 1 - frag_now->fr_literal,
length, this_add_symbol,
this_add_number, 1, NO_RELOC);
}
}
else
{
if (this_add_symbol == NULL)
{
know (is_absolute);
p = frag_more (5);
p[0] = VAX_ABSOLUTE_MODE;
md_number_to_chars (p + 1, this_add_number, 4);
if (length && length != 4)
{
as_warn (_("Length specification ignored. Address mode 9F used"));
}
}
else
{
know ((length == 0 && operandP->vop_short == ' ')
|| (length > 0 && operandP->vop_short != ' '));
if (is_undefined
#ifdef OBJ_ELF
|| S_IS_WEAK(this_add_symbol)
|| S_IS_EXTERNAL(this_add_symbol)
#endif
)
{
switch (length)
{
default: length_code = STATE_UNDF; break;
case 1: length_code = STATE_BYTE; break;
case 2: length_code = STATE_WORD; break;
case 4: length_code = STATE_LONG; break;
}
p = frag_var (rs_machine_dependent, 5, 2,
ENCODE_RELAX (STATE_PC_RELATIVE, length_code),
this_add_symbol, this_add_number,
opcode_low_byteP);
p[0] = at << 4;
}
else
{
if (length == 0)
{
know (operandP->vop_short == ' ');
length = 4;
}
p = frag_more (length + 1);
p[0] = 0xF | ((at + "?\12\14?\16"[length]) << 4);
md_number_to_chars (p + 1, this_add_number, length);
fix_new (frag_now,
p + 1 - frag_now->fr_literal,
length, this_add_symbol,
this_add_number, 1, NO_RELOC);
}
}
}
}
else
{
if (operandP->vop_mode < 0xA)
{
if (operandP->vop_access == 'v'
|| operandP->vop_access == 'a')
{
if (operandP->vop_access == 'v')
as_warn (_("Invalid operand: immediate value used as base address."));
else
as_warn (_("Invalid operand: immediate value used as address."));
}
if (length == 0
&& is_absolute && (expP->X_op != O_big)
&& operandP->vop_mode == 8
&& this_add_number < 64)
{
operandP->vop_short = 's';
}
if (operandP->vop_short == 's')
{
FRAG_APPEND_1_CHAR (this_add_number);
}
else
{
know (nbytes);
p = frag_more (nbytes + 1);
know (operandP->vop_reg == 0xF);
#ifdef OBJ_ELF
if (flag_want_pic && operandP->vop_mode == 8
&& this_add_symbol != NULL)
{
as_warn (_("Symbol used as immediate operand in PIC mode."));
}
#endif
p[0] = (operandP->vop_mode << 4) | 0xF;
if ((is_absolute) && (expP->X_op != O_big))
{
md_number_to_chars (p + 1, this_add_number, min (4, nbytes));
if (nbytes > 4)
{
memset (p + 5, '\0', nbytes - 4);
}
}
else
{
if (expP->X_op == O_big)
{
LITTLENUM_TYPE *lP;
lP = floatP->low;
if (nbytes & 1)
{
know (nbytes == 1);
p[1] = *lP;
}
else
{
for (p++; nbytes; nbytes -= 2, p += 2, lP++)
{
md_number_to_chars (p, *lP, 2);
}
}
}
else
{
fix_new (frag_now, p + 1 - frag_now->fr_literal,
nbytes, this_add_symbol,
this_add_number, 0, NO_RELOC);
}
}
}
}
else
{
know ((length == 0 && operandP->vop_short == ' ')
|| (length > 0 && operandP->vop_short != ' '));
if (length == 0)
{
if (is_absolute)
{
long test;
test = this_add_number;
if (test < 0)
test = ~test;
length = test & 0xffff8000 ? 4
: test & 0xffffff80 ? 2
: 1;
}
else
{
length = 4;
}
}
p = frag_more (1 + length);
know (operandP->vop_reg >= 0);
p[0] = operandP->vop_reg
| ((at | "?\12\14?\16"[length]) << 4);
if (is_absolute)
{
md_number_to_chars (p + 1, this_add_number, length);
}
else
{
fix_new (frag_now, p + 1 - frag_now->fr_literal,
length, this_add_symbol,
this_add_number, 0, NO_RELOC);
}
}
}
}
}
}
}
int
md_estimate_size_before_relax (fragP, segment)
fragS *fragP;
segT segment;
{
if (RELAX_LENGTH (fragP->fr_subtype) == STATE_UNDF)
{
if (S_GET_SEGMENT (fragP->fr_symbol) != segment
#ifdef OBJ_ELF
|| S_IS_WEAK (fragP->fr_symbol)
|| S_IS_EXTERNAL (fragP->fr_symbol)
#endif
)
{
int reloc_type = NO_RELOC;
char *p;
int old_fr_fix;
old_fr_fix = fragP->fr_fix;
p = fragP->fr_literal + old_fr_fix;
#ifdef OBJ_ELF
if (GOT_symbol == NULL)
GOT_symbol = symbol_find (GLOBAL_OFFSET_TABLE_NAME);
if (PLT_symbol == NULL)
PLT_symbol = symbol_find (PROCEDURE_LINKAGE_TABLE_NAME);
if ((GOT_symbol == NULL || fragP->fr_symbol != GOT_symbol)
&& (PLT_symbol == NULL || fragP->fr_symbol != PLT_symbol)
&& fragP->fr_symbol != NULL
&& flag_want_pic
&& (!S_IS_DEFINED (fragP->fr_symbol)
|| 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));
}
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;
}
}
#endif
switch (RELAX_STATE (fragP->fr_subtype))
{
case STATE_PC_RELATIVE:
p[0] |= VAX_PC_RELATIVE_MODE;
fragP->fr_fix += 1 + 4;
fix_new (fragP, old_fr_fix + 1, 4, fragP->fr_symbol,
fragP->fr_offset, 1, reloc_type);
break;
case STATE_CONDITIONAL_BRANCH:
*fragP->fr_opcode ^= 1;
p[0] = 6;
p[1] = VAX_JMP;
p[2] = VAX_PC_RELATIVE_MODE;
fragP->fr_fix += 1 + 1 + 1 + 4;
fix_new (fragP, old_fr_fix + 3, 4, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
break;
case STATE_COMPLEX_BRANCH:
p[0] = 2;
p[1] = 0;
p[2] = VAX_BRB;
p[3] = 6;
p[4] = VAX_JMP;
p[5] = VAX_PC_RELATIVE_MODE;
fragP->fr_fix += 2 + 2 + 1 + 1 + 4;
fix_new (fragP, old_fr_fix + 6, 4, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
break;
case STATE_COMPLEX_HOP:
p[0] = 2;
p[1] = VAX_BRB;
p[2] = 6;
p[3] = VAX_JMP;
p[4] = VAX_PC_RELATIVE_MODE;
fragP->fr_fix += 1 + 2 + 1 + 1 + 4;
fix_new (fragP, old_fr_fix + 5, 4, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
break;
case STATE_ALWAYS_BRANCH:
*fragP->fr_opcode += VAX_WIDEN_LONG;
p[0] = VAX_PC_RELATIVE_MODE;
fragP->fr_fix += 1 + 4;
fix_new (fragP, old_fr_fix + 1, 4, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
break;
default:
abort ();
}
frag_wane (fragP);
return fragP->fr_fix - old_fr_fix;
}
switch (RELAX_STATE (fragP->fr_subtype))
{
case STATE_PC_RELATIVE:
fragP->fr_subtype = ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE);
break;
case STATE_CONDITIONAL_BRANCH:
fragP->fr_subtype = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE);
break;
case STATE_COMPLEX_BRANCH:
fragP->fr_subtype = ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_WORD);
break;
case STATE_COMPLEX_HOP:
fragP->fr_subtype = ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_BYTE);
break;
case STATE_ALWAYS_BRANCH:
fragP->fr_subtype = ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE);
break;
}
}
if (fragP->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0]))
abort ();
return md_relax_table[fragP->fr_subtype].rlx_length;
}
#ifdef BFD_ASSEMBLER
void
md_convert_frag (headers, seg, fragP)
bfd *headers ATTRIBUTE_UNUSED;
segT seg ATTRIBUTE_UNUSED;
fragS *fragP;
#else
void
md_convert_frag (headers, seg, fragP)
object_headers *headers ATTRIBUTE_UNUSED;
segT seg ATTRIBUTE_UNUSED;
fragS *fragP;
#endif
{
char *addressP;
char *opcodeP;
short int extension = 0;
symbolS *symbolP;
long where;
know (fragP->fr_type == rs_machine_dependent);
where = fragP->fr_fix;
addressP = fragP->fr_literal + where;
opcodeP = fragP->fr_opcode;
symbolP = fragP->fr_symbol;
know (symbolP);
switch (fragP->fr_subtype)
{
case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE):
know (*addressP == 0 || *addressP == 0x10);
addressP[0] |= 0xAF;
fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
extension = 2;
break;
case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_WORD):
know (*addressP == 0 || *addressP == 0x10);
addressP[0] |= 0xCF;
fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
extension = 3;
break;
case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_LONG):
know (*addressP == 0 || *addressP == 0x10);
addressP[0] |= 0xEF;
fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
extension = 5;
break;
case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE):
fix_new (fragP, fragP->fr_fix, 1, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
extension = 1;
break;
case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD):
opcodeP[0] ^= 1;
addressP[0] = 3;
addressP[1] = VAX_BRW;
fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
extension = 4;
break;
case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_LONG):
opcodeP[0] ^= 1;
addressP[0] = 6;
addressP[1] = VAX_JMP;
addressP[2] = VAX_PC_RELATIVE_MODE;
fix_new (fragP, fragP->fr_fix + 3, 4, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
extension = 7;
break;
case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE):
fix_new (fragP, fragP->fr_fix, 1, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
extension = 1;
break;
case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_WORD):
opcodeP[0] += VAX_WIDEN_WORD;
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
1, NO_RELOC);
extension = 2;
break;
case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_LONG):
opcodeP[0] += VAX_WIDEN_LONG;
addressP[0] = VAX_PC_RELATIVE_MODE;
fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
extension = 5;
break;
case ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_WORD):
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
extension = 2;
break;
case ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_LONG):
addressP[0] = 2;
addressP[1] = 0;
addressP[2] = VAX_BRB;
addressP[3] = 6;
addressP[4] = VAX_JMP;
addressP[5] = VAX_PC_RELATIVE_MODE;
fix_new (fragP, fragP->fr_fix + 6, 4, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
extension = 10;
break;
case ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_BYTE):
fix_new (fragP, fragP->fr_fix, 1, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
extension = 1;
break;
case ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_WORD):
addressP[0] = 2;
addressP[1] = VAX_BRB;
addressP[2] = 3;
addressP[3] = VAX_BRW;
fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
extension = 6;
break;
case ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_LONG):
addressP[0] = 2;
addressP[1] = VAX_BRB;
addressP[2] = 6;
addressP[3] = VAX_JMP;
addressP[4] = VAX_PC_RELATIVE_MODE;
fix_new (fragP, fragP->fr_fix + 5, 4, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
extension = 9;
break;
default:
BAD_CASE (fragP->fr_subtype);
break;
}
fragP->fr_fix += extension;
}
#ifdef comment
void
md_ri_to_chars (the_bytes, ri)
char *the_bytes;
struct reloc_info_generic ri;
{
md_number_to_chars (the_bytes, ri.r_address, sizeof (ri.r_address));
the_bytes[6] = (ri.r_symbolnum >> 16) & 0x0ff;
the_bytes[5] = (ri.r_symbolnum >> 8) & 0x0ff;
the_bytes[4] = ri.r_symbolnum & 0x0ff;
the_bytes[7] = (((ri.r_extern << 3) & 0x08) | ((ri.r_length << 1) & 0x06) |
((ri.r_pcrel << 0) & 0x01)) & 0x0F;
}
#endif
#ifdef OBJ_AOUT
#ifndef BFD_ASSEMBLER
void
tc_aout_fix_to_chars (where, fixP, segment_address_in_file)
char *where;
fixS *fixP;
relax_addressT segment_address_in_file;
{
static const unsigned char nbytes_r_length[] = {42, 0, 1, 42, 2};
long r_symbolnum;
know (fixP->fx_addsy != NULL);
md_number_to_chars (where,
fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
4);
r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy)
? S_GET_TYPE (fixP->fx_addsy)
: fixP->fx_addsy->sy_number);
where[6] = (r_symbolnum >> 16) & 0x0ff;
where[5] = (r_symbolnum >> 8) & 0x0ff;
where[4] = r_symbolnum & 0x0ff;
where[7] = ((((!S_IS_DEFINED (fixP->fx_addsy)) << 3) & 0x08)
| ((nbytes_r_length[fixP->fx_size] << 1) & 0x06)
| (((fixP->fx_pcrel << 0) & 0x01) & 0x0f));
}
#endif
#endif
static struct hash_control *op_hash;
static const short int vax_operand_width_size[256] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 8, 0, 4, 8, 16, 0, 0, 0, 4, 0, 0,16,
0, 8, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 8, 0, 4, 8, 16, 0, 0, 0, 4, 0, 0,16,
0, 8, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
#include "opcode/vax.h"
#if (VIT_OPCODE_SYNTHETIC != 0x80000000)
You have just broken the encoding below, which assumes the sign bit
means 'I am an imaginary instruction'.
#endif
#if (VIT_OPCODE_SPECIAL != 0x40000000)
You have just broken the encoding below, which assumes the 0x40 M bit means
'I am not to be "optimised" the way normal branches are'.
#endif
static const struct vot
synthetic_votstrs[] =
{
{"jbsb", {"b-", 0xC0000010}},
{"jbr", {"b-", 0xC0000011}},
{"jr", {"b-", 0xC0000011}},
{"jneq", {"b?", 0x80000012}},
{"jnequ", {"b?", 0x80000012}},
{"jeql", {"b?", 0x80000013}},
{"jeqlu", {"b?", 0x80000013}},
{"jgtr", {"b?", 0x80000014}},
{"jleq", {"b?", 0x80000015}},
{"jgeq", {"b?", 0x80000018}},
{"jlss", {"b?", 0x80000019}},
{"jgtru", {"b?", 0x8000001a}},
{"jlequ", {"b?", 0x8000001b}},
{"jvc", {"b?", 0x8000001c}},
{"jvs", {"b?", 0x8000001d}},
{"jgequ", {"b?", 0x8000001e}},
{"jcc", {"b?", 0x8000001e}},
{"jlssu", {"b?", 0x8000001f}},
{"jcs", {"b?", 0x8000001f}},
{"jacbw", {"rwrwmwb!", 0xC000003d}},
{"jacbf", {"rfrfmfb!", 0xC000004f}},
{"jacbd", {"rdrdmdb!", 0xC000006f}},
{"jacbb", {"rbrbmbb!", 0xC000009d}},
{"jacbl", {"rlrlmlb!", 0xC00000f1}},
{"jacbg", {"rgrgmgb!", 0xC0004ffd}},
{"jacbh", {"rhrhmhb!", 0xC0006ffd}},
{"jbs", {"rlvbb?", 0x800000e0}},
{"jbc", {"rlvbb?", 0x800000e1}},
{"jbss", {"rlvbb?", 0x800000e2}},
{"jbcs", {"rlvbb?", 0x800000e3}},
{"jbsc", {"rlvbb?", 0x800000e4}},
{"jbcc", {"rlvbb?", 0x800000e5}},
{"jlbs", {"rlb?", 0x800000e8}},
{"jlbc", {"rlb?", 0x800000e9}},
{"jaoblss", {"rlmlb:", 0xC00000f2}},
{"jaobleq", {"rlmlb:", 0xC00000f3}},
{"jsobgeq", {"mlb:", 0xC00000f4}},
{"jsobgtr", {"mlb:", 0xC00000f5}},
{"", {"", 0}}
};
static const char *
vip_begin (synthetic_too, immediate, indirect, displen)
int synthetic_too;
const char *immediate, *indirect, *displen;
{
const struct vot *vP;
const char *retval = 0;
op_hash = hash_new ();
for (vP = votstrs; *vP->vot_name && !retval; vP++)
retval = hash_insert (op_hash, vP->vot_name, (PTR) &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);
#ifndef CONST_TABLE
vip_op_defaults (immediate, indirect, displen);
#endif
return retval;
}
static void
vip (vitP, instring)
struct vit *vitP;
char *instring;
{
struct vot_wot *vwP;
char *p;
char *q;
unsigned char count;
struct vop *operandp;
const char *alloperr;
char c;
vax_opcodeT oc;
if (*instring == ' ')
++instring;
for (p = instring; *p && *p != ' '; p++);;
if (p - instring == 0)
{
vitP->vit_error = _("No operator");
count = 0;
memset (vitP->vit_opcode, '\0', sizeof (vitP->vit_opcode));
}
else
{
c = *p;
*p = '\0';
vwP = (struct vot_wot *) hash_find (op_hash, instring);
*p = c;
if (vwP == 0)
{
vitP->vit_error = _("Unknown operator");
count = 0;
memset (vitP->vit_opcode, '\0', sizeof (vitP->vit_opcode));
}
else
{
const char *howp;
oc = vwP->vot_code;
vitP->vit_opcode_nbytes = (oc & 0xFF) >= 0xFD ? 2 : 1;
md_number_to_chars (vitP->vit_opcode, oc, 4);
count = 0;
instring = p;
alloperr = "";
for (howp = vwP->vot_how, operandp = vitP->vit_operand;
!(alloperr && *alloperr) && *howp;
operandp++, howp += 2)
{
if (!howp[1])
as_fatal (_("odd number of bytes in operand description"));
else if (*instring)
{
for (q = instring; (c = *q) && c != ','; q++)
;
*q = 0;
operandp->vop_width = howp[1];
operandp->vop_nbytes = vax_operand_width_size[(unsigned) howp[1]];
operandp->vop_access = howp[0];
vip_op (instring, operandp);
*q = c;
if (operandp->vop_error)
alloperr = _("Bad operand");
instring = q + (c ? 1 : 0);
count++;
}
else
alloperr = _("Not enough operands");
}
if (!*alloperr)
{
if (*instring == ' ')
instring++;
if (*instring)
alloperr = _("Too many operands");
}
vitP->vit_error = alloperr;
}
}
vitP->vit_operands = count;
}
#ifdef test
struct vit myvit;
char answer[100];
char *mybug;
int mycount;
struct vop *myvop;
int mysynth;
char my_immediate[200];
char my_indirect[200];
char my_displen[200];
main ()
{
char *p;
printf ("0 means no synthetic instructions. ");
printf ("Value for vip_begin? ");
gets (answer);
sscanf (answer, "%d", &mysynth);
printf ("Synthetic opcodes %s be included.\n", mysynth ? "will" : "will not");
printf ("enter immediate symbols eg enter # ");
gets (my_immediate);
printf ("enter indirect symbols eg enter @ ");
gets (my_indirect);
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);
}
printf ("An empty input line will quit you from the vax instruction parser\n");
for (;;)
{
printf ("vax instruction: ");
fflush (stdout);
gets (answer);
if (!*answer)
{
break;
}
vip (&myvit, answer);
if (*myvit.vit_error)
{
printf ("ERR:\"%s\"\n", myvit.vit_error);
}
printf ("opcode=");
for (mycount = myvit.vit_opcode_nbytes, p = myvit.vit_opcode;
mycount;
mycount--, p++
)
{
printf ("%02x ", *p & 0xFF);
}
printf (" operand count=%d.\n", mycount = myvit.vit_operands);
for (myvop = myvit.vit_operand; mycount; mycount--, myvop++)
{
printf ("mode=%xx reg=%xx ndx=%xx len='%c'=%c%c%d. expr=\"",
myvop->vop_mode, myvop->vop_reg, myvop->vop_ndx,
myvop->vop_short, myvop->vop_access, myvop->vop_width,
myvop->vop_nbytes);
for (p = myvop->vop_expr_begin; p <= myvop->vop_expr_end; p++)
{
putchar (*p);
}
printf ("\"\n");
if (myvop->vop_error)
{
printf (" err:\"%s\"\n", myvop->vop_error);
}
if (myvop->vop_warn)
{
printf (" wrn:\"%s\"\n", myvop->vop_warn);
}
}
}
vip_end ();
exit (EXIT_SUCCESS);
}
#endif
#include "safe-ctype.h"
#define AP (12)
#define FP (13)
#define SP (14)
#define PC (15)
int
vax_reg_parse (c1, c2, c3, c4)
char c1, c2, c3, c4;
{
int retval;
retval = -1;
#ifdef OBJ_ELF
if (c1 != '%')
return retval;
c1 = c2;
c2 = c3;
c3 = c4;
#endif
#ifdef OBJ_VMS
if (c4 != 0)
return retval;
#endif
#ifdef OBJ_AOUT
if (c1 == '%')
{
c1 = c2;
c2 = c3;
c3 = c4;
}
else if (c3 && c4)
return retval;
#endif
c1 = TOLOWER (c1);
c2 = TOLOWER (c2);
if (ISDIGIT (c2) && c1 == 'r')
{
retval = c2 - '0';
if (ISDIGIT (c3))
{
retval = retval * 10 + c3 - '0';
retval = (retval > 15) ? -1 : retval;
}
else if (c3)
retval = -1;
}
else if (c3)
retval = -1;
else if (c2 == 'p')
{
switch (c1)
{
case 's':
retval = SP;
break;
case 'f':
retval = FP;
break;
case 'a':
retval = AP;
break;
default:
retval = -1;
}
}
else if (c1 == 'p' && c2 == 'c')
retval = PC;
else
retval = -1;
return (retval);
}
#define VIP_IMMEDIATE 01
#define VIP_INDIRECT 02
#define VIP_DISPLEN 04
#define IMMEDIATEP(c) (vip_metacharacters [(c)&0xff]&VIP_IMMEDIATE)
#define INDIRECTP(c) (vip_metacharacters [(c)&0xff]&VIP_INDIRECT)
#define DISPLENP(c) (vip_metacharacters [(c)&0xff]&VIP_DISPLEN)
#if defined(CONST_TABLE)
#define _ 0,
#define I VIP_IMMEDIATE,
#define S VIP_INDIRECT,
#define D VIP_DISPLEN,
static const char
vip_metacharacters[256] =
{
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ I _ _ _ _ _ S _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
D _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
};
#undef _
#undef I
#undef S
#undef D
#else
static char vip_metacharacters[256];
static void
vip_op_1 (bit, syms)
int bit;
const char *syms;
{
unsigned char t;
while ((t = *syms++) != 0)
vip_metacharacters[t] |= bit;
}
static void
vip_op_defaults (immediate, indirect, displen)
const char *immediate;
const char *indirect;
const char *displen;
{
vip_op_1 (VIP_IMMEDIATE, immediate);
vip_op_1 (VIP_INDIRECT, indirect);
vip_op_1 (VIP_DISPLEN, displen);
}
#endif
static void
vip_op (optext, vopP)
char *optext;
struct vop *vopP;
{
char *p;
char *q;
int at;
char len;
int hash;
int sign = 0;
int paren = 0;
int reg = 0;
int ndx = 0;
const char *err;
const char *wrn;
char *oldq = NULL;
int mode = 0;
char access_mode;
char width;
access_mode = vopP->vop_access;
width = vopP->vop_width;
err = wrn = 0;
p = optext;
if (*p == ' ')
p++;
if ((at = INDIRECTP (*p)) != 0)
{
p++;
if (*p == ' ')
p++;
}
{
char c;
c = *p;
c = TOLOWER (c);
if (DISPLENP (p[1]) && strchr ("bilws", len = c))
p += 2;
else
len = ' ';
}
if (*p == ' ')
p++;
if ((hash = IMMEDIATEP (*p)) != 0)
p++;
for (q = p; *q; q++)
;
q--;
if (*q == ' ' && q >= p)
q--;
if (*q == ']')
{
while (q >= p && *q != '[')
q--;
if (q < p)
err = _("no '[' to match ']'");
else
{
if (q[3] == ']')
ndx = vax_reg_parse (q[1], q[2], 0, 0);
else if (q[4] == ']')
ndx = vax_reg_parse (q[1], q[2], q[3], 0);
else if (q[5] == ']')
ndx = vax_reg_parse (q[1], q[2], q[3], q[4]);
else
ndx = -1;
if (ndx < 0)
err = _("bad register in []");
else if (ndx == PC)
err = _("[PC] index banned");
else
q--;
}
}
else
ndx = -1;
if (*q == ' ' && q >= p)
q--;
if (!err || !*err)
{
sign = 0;
if (q > p + 3 && *q == '+' && q[-1] == ')')
{
sign = 1;
q--;
}
if (*q == ')' && q > p + 2)
{
paren = 1;
while (q >= p && *q != '(')
q--;
if (q < p)
err = _("no '(' to match ')'");
else
{
if (q[3] == ')')
reg = vax_reg_parse (q[1], q[2], 0, 0);
else if (q[4] == ')')
reg = vax_reg_parse (q[1], q[2], q[3], 0);
else if (q[5] == ')')
reg = vax_reg_parse (q[1], q[2], q[3], q[4]);
else
reg = -1;
if (reg < 0)
{
paren = 0;
while (*q != ')')
q++;
}
else
q--;
}
}
else
paren = 0;
if (!err || !*err)
{
if (paren && sign < 1)
{
if (*q == '-')
{
sign = -1;
q--;
}
}
if (!paren)
{
if (*q == ' ' && q >= p)
q--;
if (q > p && q < p + 4)
reg = vax_reg_parse (p[0], p[1],
q < p + 2 ? 0 : p[2],
q < p + 3 ? 0 : p[3]);
else
reg = -1;
if (reg >= 0)
{
oldq = q;
q = p - 1;
}
}
}
}
if ((!err || !*err) && access_mode == 'b')
{
if (at || hash || sign || paren || ndx >= 0 || reg >= 0 || len != ' ')
err = _("invalid branch operand");
else
err = " ";
}
#ifdef NEVER
if ((!err || !*err) && access_mode == ' ')
{
if (at)
err = _("address prohibits @");
else if (hash)
err = _("address prohibits #");
else if (sign)
{
if (sign < 0)
err = _("address prohibits -()");
else
err = _("address prohibits ()+");
}
else if (paren)
err = _("address prohibits ()");
else if (ndx >= 0)
err = _("address prohibits []");
else if (reg >= 0)
err = _("address prohibits register");
else if (len != ' ')
err = _("address prohibits displacement length specifier");
else
{
err = " ";
mode = 0;
}
}
#endif
if ((!err || !*err) && len == 's')
{
if (!hash || paren || at || ndx >= 0)
err = _("invalid operand of S^#");
else
{
if (reg >= 0)
{
q = oldq;
reg = 0;
}
if (p > q)
err = _("S^# needs expression");
else if (access_mode == 'r')
{
err = " ";
mode = 0;
}
else
err = _("S^# may only read-access");
}
}
if ((!err || !*err) && sign < 0)
{
if (len != ' ' || hash || at || p <= q)
err = _("invalid operand of -()");
else
{
err = " ";
mode = 7;
if (reg == PC)
wrn = _("-(PC) unpredictable");
else if (reg == ndx)
wrn = _("[]index same as -()register: unpredictable");
}
}
if (paren && !sign && !hash && !at && len == ' ' && p > q)
{
at = 1;
paren = 0;
}
if ((!err || !*err) && sign > 0)
{
if (len != ' ' || hash || p <= q)
err = _("invalid operand of ()+");
else
{
err = " ";
mode = 8 + (at ? 1 : 0);
if (reg == PC)
wrn = _("(PC)+ unpredictable");
else if (reg == ndx)
wrn = _("[]index same as ()+register: unpredictable");
}
}
if ((!err || !*err) && hash)
{
if (len != 'i' && len != ' ')
err = _("# conflicts length");
else if (paren)
err = _("# bars register");
else
{
if (reg >= 0)
{
q = oldq;
reg = -1;
}
err = " ";
if (at && access_mode == 'a')
vopP->vop_nbytes = 4;
mode = (at ? 9 : 8);
reg = PC;
if ((access_mode == 'm' || access_mode == 'w') && !at)
wrn = _("writing or modifying # is unpredictable");
}
}
if ((!err || !*err) && !paren && reg >= 0)
{
if (len != ' ')
err = _("length not needed");
else if (at)
{
err = " ";
mode = 6;
}
else if (ndx >= 0)
err = _("can't []index a register, because it has no address");
else if (access_mode == 'a')
err = _("a register has no address");
else
{
if ((vopP->vop_nbytes + reg * 4) > 60)
wrn = _("PC part of operand unpredictable");
err = " ";
mode = 5;
}
}
if (!err || !*err)
{
err = " ";
mode = 10 + (at ? 1 : 0);
switch (len)
{
case 'l':
mode += 2;
case 'w':
mode += 2;
case ' ':
case 'b':
break;
}
}
if (*err == ' ')
err = 0;
vopP->vop_mode = mode;
vopP->vop_reg = reg;
vopP->vop_short = len;
vopP->vop_expr_begin = p;
vopP->vop_expr_end = q;
vopP->vop_ndx = ndx;
vopP->vop_error = err;
vopP->vop_warn = wrn;
}
#ifdef TEST
#include <stdio.h>
char answer[100];
char *p;
char *myerr;
char *mywrn;
char *mybug;
char myaccess;
char mywidth;
char mymode;
char myreg;
char mylen;
char *myleft;
char *myright;
char myndx;
int my_operand_length;
char my_immediate[200];
char my_indirect[200];
char my_displen[200];
main ()
{
printf ("enter immediate symbols eg enter # ");
gets (my_immediate);
printf ("enter indirect symbols eg enter @ ");
gets (my_indirect);
printf ("enter displen symbols eg enter ^ ");
gets (my_displen);
vip_op_defaults (my_immediate, my_indirect, my_displen);
for (;;)
{
printf ("access,width (eg 'ab' or 'wh') [empty line to quit] : ");
fflush (stdout);
gets (answer);
if (!answer[0])
exit (EXIT_SUCCESS);
myaccess = answer[0];
mywidth = answer[1];
switch (mywidth)
{
case 'b':
my_operand_length = 1;
break;
case 'd':
my_operand_length = 8;
break;
case 'f':
my_operand_length = 4;
break;
case 'g':
my_operand_length = 16;
break;
case 'h':
my_operand_length = 32;
break;
case 'l':
my_operand_length = 4;
break;
case 'o':
my_operand_length = 16;
break;
case 'q':
my_operand_length = 8;
break;
case 'w':
my_operand_length = 2;
break;
case '!':
case '?':
case '-':
my_operand_length = 0;
break;
default:
my_operand_length = 2;
printf ("I dn't understand access width %c\n", mywidth);
break;
}
printf ("VAX assembler instruction operand: ");
fflush (stdout);
gets (answer);
mybug = vip_op (answer, myaccess, mywidth, my_operand_length,
&mymode, &myreg, &mylen, &myleft, &myright, &myndx,
&myerr, &mywrn);
if (*myerr)
{
printf ("error: \"%s\"\n", myerr);
if (*mybug)
printf (" bug: \"%s\"\n", mybug);
}
else
{
if (*mywrn)
printf ("warning: \"%s\"\n", mywrn);
mumble ("mode", mymode);
mumble ("register", myreg);
mumble ("index", myndx);
printf ("width:'%c' ", mylen);
printf ("expression: \"");
while (myleft <= myright)
putchar (*myleft++);
printf ("\"\n");
}
}
}
mumble (text, value)
char *text;
int value;
{
printf ("%s:", text);
if (value >= 0)
printf ("%xx", value);
else
printf ("ABSENT");
printf (" ");
}
#endif
int md_short_jump_size = 3;
int md_long_jump_size = 6;
const int md_reloc_size = 8;
void
md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
char *ptr;
addressT from_addr;
addressT to_addr ATTRIBUTE_UNUSED;
fragS *frag ATTRIBUTE_UNUSED;
symbolS *to_symbol ATTRIBUTE_UNUSED;
{
valueT offset;
offset = to_addr - (from_addr + 1 + 2);
*ptr++ = VAX_BRW;
md_number_to_chars (ptr, offset, 2);
}
void
md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
char *ptr;
addressT from_addr ATTRIBUTE_UNUSED;
addressT to_addr;
fragS *frag;
symbolS *to_symbol;
{
valueT offset;
offset = to_addr - S_GET_VALUE (to_symbol);
*ptr++ = VAX_JMP;
*ptr++ = VAX_ABSOLUTE_MODE;
md_number_to_chars (ptr, offset, 4);
fix_new (frag, ptr - frag->fr_literal, 4, to_symbol, (long) 0, 0, NO_RELOC);
}
#ifdef OBJ_VMS
const char *md_shortopts = "d:STt:V+1h:Hv::";
#elif defined(OBJ_ELF)
const char *md_shortopts = "d:STt:VkKQ:";
#else
const char *md_shortopts = "d:STt:V";
#endif
struct option md_longopts[] = {
#ifdef OBJ_ELF
#define OPTION_PIC (OPTION_MD_BASE)
{"pic", no_argument, NULL, OPTION_PIC},
#endif
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
int
md_parse_option (c, arg)
int c;
char *arg;
{
switch (c)
{
case 'S':
as_warn (_("SYMBOL TABLE not implemented"));
break;
case 'T':
as_warn (_("TOKEN TRACE not implemented"));
break;
case 'd':
as_warn (_("Displacement length %s ignored!"), arg);
break;
case 't':
as_warn (_("I don't need or use temp. file \"%s\"."), arg);
break;
case 'V':
as_warn (_("I don't use an interpass file! -V ignored"));
break;
#ifdef OBJ_VMS
case '+':
flag_hash_long_names = 1;
break;
case '1':
flag_one = 1;
break;
case 'H':
flag_show_after_trunc = 1;
break;
case 'h':
{
extern char vms_name_mapping;
vms_name_mapping = atoi (arg);
flag_no_hash_mixed_case = 1;
}
break;
case 'v':
{
extern char *compiler_version_string;
if (!arg || !*arg || access (arg, 0) == 0)
return 0;
compiler_version_string = arg;
}
break;
#endif
#ifdef OBJ_ELF
case OPTION_PIC:
case 'k':
flag_want_pic = 1;
break;
case 'Q':
break;
#endif
default:
return 0;
}
return 1;
}
void
md_show_usage (stream)
FILE *stream;
{
fprintf (stream, _("\
VAX options:\n\
-d LENGTH ignored\n\
-J ignored\n\
-S ignored\n\
-t FILE ignored\n\
-T ignored\n\
-V ignored\n"));
#ifdef OBJ_VMS
fprintf (stream, _("\
VMS options:\n\
-+ hash encode names longer than 31 characters\n\
-1 `const' handling compatible with gcc 1.x\n\
-H show new symbol after hash truncation\n\
-h NUM don't hash mixed-case names, and adjust case:\n\
0 = upper, 2 = lower, 3 = preserve case\n\
-v\"VERSION\" code being assembled was produced by compiler \"VERSION\"\n"));
#endif
}
symbolS *
md_undefined_symbol (name)
char *name ATTRIBUTE_UNUSED;
{
return 0;
}
valueT
md_section_align (segment, size)
segT segment ATTRIBUTE_UNUSED;
valueT size;
{
return size;
}
long
md_pcrel_from (fixP)
fixS *fixP;
{
return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
}
#ifdef OBJ_AOUT
#ifndef BFD_ASSEMBLER
void
tc_headers_hook(headers)
object_headers *headers;
{
#ifdef TE_NetBSD
N_SET_INFO(headers->header, OMAGIC, M_VAX4K_NETBSD, 0);
headers->header.a_info = htonl (headers->header.a_info);
#endif
}
#endif
#endif
#ifdef BFD_ASSEMBLER
arelent *
tc_gen_reloc (section, fixp)
asection *section ATTRIBUTE_UNUSED;
fixS *fixp;
{
arelent *reloc;
bfd_reloc_code_real_type code;
if (fixp->fx_tcbit)
abort();
if (fixp->fx_r_type != BFD_RELOC_NONE)
{
code = fixp->fx_r_type;
if (fixp->fx_pcrel)
{
switch (code)
{
case BFD_RELOC_8_PCREL:
case BFD_RELOC_16_PCREL:
case BFD_RELOC_32_PCREL:
#ifdef OBJ_ELF
case BFD_RELOC_8_GOT_PCREL:
case BFD_RELOC_16_GOT_PCREL:
case BFD_RELOC_32_GOT_PCREL:
case BFD_RELOC_8_PLT_PCREL:
case BFD_RELOC_16_PLT_PCREL:
case BFD_RELOC_32_PLT_PCREL:
#endif
break;
default:
as_bad_where (fixp->fx_file, fixp->fx_line,
_("Cannot make %s relocation PC relative"),
bfd_get_reloc_code_name (code));
}
}
}
else
{
#define F(SZ,PCREL) (((SZ) << 1) + (PCREL))
switch (F (fixp->fx_size, fixp->fx_pcrel))
{
#define MAP(SZ,PCREL,TYPE) case F(SZ,PCREL): code = (TYPE); break
MAP (1, 0, BFD_RELOC_8);
MAP (2, 0, BFD_RELOC_16);
MAP (4, 0, BFD_RELOC_32);
MAP (1, 1, BFD_RELOC_8_PCREL);
MAP (2, 1, BFD_RELOC_16_PCREL);
MAP (4, 1, BFD_RELOC_32_PCREL);
default:
abort ();
}
}
#undef F
#undef MAP
reloc = (arelent *) xmalloc (sizeof (arelent));
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;
#ifndef OBJ_ELF
if (fixp->fx_pcrel)
reloc->addend = fixp->fx_addnumber;
else
reloc->addend = 0;
#else
reloc->addend = fixp->fx_offset;
#endif
reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
assert (reloc->howto != 0);
return reloc;
}
#endif