/* tc-i960.c - All the i80960-specific stuff
- Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1989, 90, 91, 92, 93, 94, 95, 96, 97, 98, 1999
+ Free Software Foundation, Inc.
This file is part of GAS.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ along with GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
/* See comment on md_parse_option for 80960-specific invocation options. */
-/******************************************************************************
- * i80690 NOTE!!!:
- * Header, symbol, and relocation info will be used on the host machine
- * only -- only executable code is actually downloaded to the i80960.
- * Therefore, leave all such information in host byte order.
- *
- * (That's a slight lie -- we DO download some header information, but
- * the downloader converts the file format and corrects the byte-ordering
- * of the relevant fields while doing so.)
- *
- * ==> THIS IS NO LONGER TRUE USING BFD. WE CAN GENERATE ANY BYTE ORDER
- * FOR THE HEADER, AND READ ANY BYTE ORDER. PREFERENCE WOULD BE TO
- * USE LITTLE-ENDIAN BYTE ORDER THROUGHOUT, REGARDLESS OF HOST. <==
- *
- ***************************************************************************** */
-
/* There are 4 different lengths of (potentially) symbol-based displacements
- * in the 80960 instruction set, each of which could require address fix-ups
- * and (in the case of external symbols) emission of relocation directives:
- *
- * 32-bit (MEMB)
- * This is a standard length for the base assembler and requires no
- * special action.
- *
- * 13-bit (COBR)
- * This is a non-standard length, but the base assembler has a hook for
- * bit field address fixups: the fixS structure can point to a descriptor
- * of the field, in which case our md_number_to_field() routine gets called
- * to process it.
- *
- * I made the hook a little cleaner by having fix_new() (in the base
- * assembler) return a pointer to the fixS in question. And I made it a
- * little simpler by storing the field size (in this case 13) instead of
- * of a pointer to another structure: 80960 displacements are ALWAYS
- * stored in the low-order bits of a 4-byte word.
- *
- * Since the target of a COBR cannot be external, no relocation directives
- * for this size displacement have to be generated. But the base assembler
- * had to be modified to issue error messages if the symbol did turn out
- * to be external.
- *
- * 24-bit (CTRL)
- * Fixups are handled as for the 13-bit case (except that 24 is stored
- * in the fixS).
- *
- * The relocation directive generated is the same as that for the 32-bit
- * displacement, except that it's PC-relative (the 32-bit displacement
- * never is). The i80960 version of the linker needs a mod to
- * distinguish and handle the 24-bit case.
- *
- * 12-bit (MEMA)
- * MEMA formats are always promoted to MEMB (32-bit) if the displacement
- * is based on a symbol, because it could be relocated at link time.
- * The only time we use the 12-bit format is if an absolute value of
- * less than 4096 is specified, in which case we need neither a fixup nor
- * a relocation directive.
- */
+ in the 80960 instruction set, each of which could require address fix-ups
+ and (in the case of external symbols) emission of relocation directives:
+
+ 32-bit (MEMB)
+ This is a standard length for the base assembler and requires no
+ special action.
+
+ 13-bit (COBR)
+ This is a non-standard length, but the base assembler has a
+ hook for bit field address fixups: the fixS structure can
+ point to a descriptor of the field, in which case our
+ md_number_to_field() routine gets called to process it.
+
+ I made the hook a little cleaner by having fix_new() (in the base
+ assembler) return a pointer to the fixS in question. And I made it a
+ little simpler by storing the field size (in this case 13) instead of
+ of a pointer to another structure: 80960 displacements are ALWAYS
+ stored in the low-order bits of a 4-byte word.
+
+ Since the target of a COBR cannot be external, no relocation
+ directives for this size displacement have to be generated.
+ But the base assembler had to be modified to issue error
+ messages if the symbol did turn out to be external.
+
+ 24-bit (CTRL)
+ Fixups are handled as for the 13-bit case (except that 24 is stored
+ in the fixS).
+
+ The relocation directive generated is the same as that for the 32-bit
+ displacement, except that it's PC-relative (the 32-bit displacement
+ never is). The i80960 version of the linker needs a mod to
+ distinguish and handle the 24-bit case.
+
+ 12-bit (MEMA)
+ MEMA formats are always promoted to MEMB (32-bit) if the displacement
+ is based on a symbol, because it could be relocated at link time.
+ The only time we use the 12-bit format is if an absolute value of
+ less than 4096 is specified, in which case we need neither a fixup nor
+ a relocation directive. */
#include <stdio.h>
#include <ctype.h>
#include "opcode/i960.h"
+#if defined (OBJ_AOUT) || defined (OBJ_BOUT)
+
+#define TC_S_IS_SYSPROC(s) ((1<=S_GET_OTHER(s)) && (S_GET_OTHER(s)<=32))
+#define TC_S_IS_BALNAME(s) (S_GET_OTHER(s) == N_BALNAME)
+#define TC_S_IS_CALLNAME(s) (S_GET_OTHER(s) == N_CALLNAME)
+#define TC_S_IS_BADPROC(s) ((S_GET_OTHER(s) != 0) && !TC_S_IS_CALLNAME(s) && !TC_S_IS_BALNAME(s) && !TC_S_IS_SYSPROC(s))
+
+#define TC_S_SET_SYSPROC(s, p) (S_SET_OTHER((s), (p)+1))
+#define TC_S_GET_SYSPROC(s) (S_GET_OTHER(s)-1)
+
+#define TC_S_FORCE_TO_BALNAME(s) (S_SET_OTHER((s), N_BALNAME))
+#define TC_S_FORCE_TO_CALLNAME(s) (S_SET_OTHER((s), N_CALLNAME))
+#define TC_S_FORCE_TO_SYSPROC(s) {;}
+
+#else /* ! OBJ_A/BOUT */
+#ifdef OBJ_COFF
+
+#define TC_S_IS_SYSPROC(s) (S_GET_STORAGE_CLASS(s) == C_SCALL)
+#define TC_S_IS_BALNAME(s) (SF_GET_BALNAME(s))
+#define TC_S_IS_CALLNAME(s) (SF_GET_CALLNAME(s))
+#define TC_S_IS_BADPROC(s) (TC_S_IS_SYSPROC(s) && TC_S_GET_SYSPROC(s) < 0 && 31 < TC_S_GET_SYSPROC(s))
+
+#define TC_S_SET_SYSPROC(s, p) ((s)->sy_symbol.ost_auxent[1].x_sc.x_stindx = (p))
+#define TC_S_GET_SYSPROC(s) ((s)->sy_symbol.ost_auxent[1].x_sc.x_stindx)
+
+#define TC_S_FORCE_TO_BALNAME(s) (SF_SET_BALNAME(s))
+#define TC_S_FORCE_TO_CALLNAME(s) (SF_SET_CALLNAME(s))
+#define TC_S_FORCE_TO_SYSPROC(s) (S_SET_STORAGE_CLASS((s), C_SCALL))
+
+#else /* ! OBJ_COFF */
+#ifdef OBJ_ELF
+#define TC_S_IS_SYSPROC(s) 0
+
+#define TC_S_IS_BALNAME(s) 0
+#define TC_S_IS_CALLNAME(s) 0
+#define TC_S_IS_BADPROC(s) 0
+
+#define TC_S_SET_SYSPROC(s, p)
+#define TC_S_GET_SYSPROC(s) 0
+
+#define TC_S_FORCE_TO_BALNAME(s)
+#define TC_S_FORCE_TO_CALLNAME(s)
+#define TC_S_FORCE_TO_SYSPROC(s)
+#else
+ #error COFF, a.out, b.out, and ELF are the only supported formats.
+#endif /* ! OBJ_ELF */
+#endif /* ! OBJ_COFF */
+#endif /* ! OBJ_A/BOUT */
+
extern char *input_line_pointer;
-extern struct hash_control *po_hash;
-extern char *next_object_file_charP;
+#if !defined (BFD_ASSEMBLER) && !defined (BFD)
#ifdef OBJ_COFF
const int md_reloc_size = sizeof (struct reloc);
#else /* OBJ_COFF */
const int md_reloc_size = sizeof (struct relocation_info);
#endif /* OBJ_COFF */
+#endif
-/***************************
- * Local i80960 routines *
- ************************** */
+/* Local i80960 routines. */
static void brcnt_emit (); /* Emit branch-prediction instrumentation code */
static char *brlab_next (); /* Return next branch local label */
static void syntax (); /* Give syntax error */
static int targ_has_sfr (); /* Target chip supports spec-func register? */
static int targ_has_iclass (); /* Target chip supports instruction set? */
-/* static void unlink_sym(); *//* Remove a symbol from the symbol list */
/* See md_parse_option() for meanings of these options */
static char norelax; /* True if -norelax switch seen */
-static char instrument_branches;/* True if -b switch seen */
+static char instrument_branches; /* True if -b switch seen */
/* Characters that always start a comment.
- * If the pre-processor is disabled, these aren't very useful.
+ If the pre-processor is disabled, these aren't very useful.
*/
const char comment_chars[] = "#";
/* Characters that only start a comment at the beginning of
- * a line. If the line seems to have the form '# 123 filename'
- * .line and .file directives will appear in the pre-processed output.
- *
- * Note that input_file.c hand checks for '#' at the beginning of the
- * first line of the input file. This is because the compiler outputs
- * #NO_APP at the beginning of its output.
+ a line. If the line seems to have the form '# 123 filename'
+ .line and .file directives will appear in the pre-processed output.
+
+ Note that input_file.c hand checks for '#' at the beginning of the
+ first line of the input file. This is because the compiler outputs
+ #NO_APP at the beginning of its output.
*/
/* Also note that comments started like this one will always work. */
const char EXP_CHARS[] = "eE";
/* Chars that mean this number is a floating point constant,
- * as in 0f12.456 or 0d1.2345e12
+ as in 0f12.456 or 0d1.2345e12
*/
const char FLT_CHARS[] = "fFdDtT";
/* Table used by base assembler to relax addresses based on varying length
- * instructions. The fields are:
- * 1) most positive reach of this state,
- * 2) most negative reach of this state,
- * 3) how many bytes this mode will add to the size of the current frag
- * 4) which index into the table to try if we can't fit into this one.
- *
- * For i80960, the only application is the (de-)optimization of cobr
- * instructions into separate compare and branch instructions when a 13-bit
- * displacement won't hack it.
+ instructions. The fields are:
+ 1) most positive reach of this state,
+ 2) most negative reach of this state,
+ 3) how many bytes this mode will add to the size of the current frag
+ 4) which index into the table to try if we can't fit into this one.
+
+ For i80960, the only application is the (de-)optimization of cobr
+ instructions into separate compare and branch instructions when a 13-bit
+ displacement won't hack it.
*/
-const relax_typeS
- md_relax_table[] =
+const relax_typeS md_relax_table[] =
{
{0, 0, 0, 0}, /* State 0 => no more relaxation possible */
{4088, -4096, 0, 2}, /* State 1: conditional branch (cobr) */
{0x800000 - 8, -0x800000, 4, 0}, /* State 2: compare (reg) & branch (ctrl) */
};
+static void s_endian PARAMS ((int));
/* These are the machine dependent pseudo-ops.
- *
- * This table describes all the machine specific pseudo-ops the assembler
- * has to support. The fields are:
- * pseudo-op name without dot
- * function to call to execute this pseudo-op
- * integer arg to pass to the function
+
+ This table describes all the machine specific pseudo-ops the assembler
+ has to support. The fields are:
+ pseudo-op name without dot
+ function to call to execute this pseudo-op
+ integer arg to pass to the function
*/
#define S_LEAFPROC 1
#define S_SYSPROC 2
const pseudo_typeS md_pseudo_table[] =
{
{"bss", s_lcomm, 1},
+ {"endian", s_endian, 0},
{"extended", float_cons, 't'},
{"leafproc", parse_po, S_LEAFPROC},
{"sysproc", parse_po, S_SYSPROC},
{"word", cons, 4},
- {"quad", big_cons, 16},
+ {"quad", cons, 16},
{0, 0, 0}
};
};
-/* Number and assembler mnemonic for all registers that can appear in operands */
-static struct
+/* Number and assembler mnemonic for all registers that can appear in
+ operands. */
+static const struct
{
char *reg_name;
int reg_num;
}
-
regnames[] =
{
{ "pfp", 0 },
{ "sf30", 62 },
{ "sf31", 63 },
- /* Numbers for floating point registers are for assembler internal use
- * only: they are scaled back to [0-3] for binary output.
- */
+ /* Numbers for floating point registers are for assembler internal
+ use only: they are scaled back to [0-3] for binary output. */
#define FP0 64
{ "fp0", 64 },
#define IS_SF_REG(n) ((SF0 <= (n)) && ((n) < FP0))
#define IS_FP_REG(n) ((n) >= FP0)
-/* Number and assembler mnemonic for all registers that can appear as 'abase'
- * (indirect addressing) registers.
- */
-static struct
+/* Number and assembler mnemonic for all registers that can appear as
+ 'abase' (indirect addressing) registers. */
+static const struct
{
char *areg_name;
int areg_num;
}
-
aregs[] =
{
{ "(pfp)", 0 },
#define ARCH_KB 2
#define ARCH_MC 3
#define ARCH_CA 4
+#define ARCH_JX 5
+#define ARCH_HX 6
int architecture = ARCH_ANY; /* Architecture requested on invocation line */
int iclasses_seen; /* OR of instruction classes (I_* constants)
- * for which we've actually assembled
- * instructions.
+ * for which we've actually assembled
+ * instructions.
*/
/* BRANCH-PREDICTION INSTRUMENTATION
- *
- * The following supports generation of branch-prediction instrumentation
- * (turned on by -b switch). The instrumentation collects counts
- * of branches taken/not-taken for later input to a utility that will
- * set the branch prediction bits of the instructions in accordance with
- * the behavior observed. (Note that the KX series does not have
- * brach-prediction.)
- *
- * The instrumentation consists of:
- *
- * (1) before and after each conditional branch, a call to an external
- * routine that increments and steps over an inline counter. The
- * counter itself, initialized to 0, immediately follows the call
- * instruction. For each branch, the counter following the branch
- * is the number of times the branch was not taken, and the difference
- * between the counters is the number of times it was taken. An
- * example of an instrumented conditional branch:
- *
- * call BR_CNT_FUNC
- * .word 0
- * LBRANCH23: be label
- * call BR_CNT_FUNC
- * .word 0
- *
- * (2) a table of pointers to the instrumented branches, so that an
- * external postprocessing routine can locate all of the counters.
- * the table begins with a 2-word header: a pointer to the next in
- * a linked list of such tables (initialized to 0); and a count
- * of the number of entries in the table (exclusive of the header.
- *
- * Note that input source code is expected to already contain calls
- * an external routine that will link the branch local table into a
- * list of such tables.
+
+ The following supports generation of branch-prediction instrumentation
+ (turned on by -b switch). The instrumentation collects counts
+ of branches taken/not-taken for later input to a utility that will
+ set the branch prediction bits of the instructions in accordance with
+ the behavior observed. (Note that the KX series does not have
+ brach-prediction.)
+
+ The instrumentation consists of:
+
+ (1) before and after each conditional branch, a call to an external
+ routine that increments and steps over an inline counter. The
+ counter itself, initialized to 0, immediately follows the call
+ instruction. For each branch, the counter following the branch
+ is the number of times the branch was not taken, and the difference
+ between the counters is the number of times it was taken. An
+ example of an instrumented conditional branch:
+
+ call BR_CNT_FUNC
+ .word 0
+ LBRANCH23: be label
+ call BR_CNT_FUNC
+ .word 0
+
+ (2) a table of pointers to the instrumented branches, so that an
+ external postprocessing routine can locate all of the counters.
+ the table begins with a 2-word header: a pointer to the next in
+ a linked list of such tables (initialized to 0); and a count
+ of the number of entries in the table (exclusive of the header.
+
+ Note that input source code is expected to already contain calls
+ an external routine that will link the branch local table into a
+ list of such tables.
*/
-static int br_cnt; /* Number of branches instrumented so far.
- * Also used to generate unique local labels
- * for each instrumented branch
- */
+/* Number of branches instrumented so far. Also used to generate
+ unique local labels for each instrumented branch. */
+static int br_cnt;
#define BR_LABEL_BASE "LBRANCH"
-/* Basename of local labels on instrumented
- * branches, to avoid conflict with compiler-
- * generated local labels.
- */
+/* Basename of local labels on instrumented branches, to avoid
+ conflict with compiler- generated local labels. */
#define BR_CNT_FUNC "__inc_branch"
-/* Name of the external routine that will
- * increment (and step over) an inline counter.
- */
+/* Name of the external routine that will increment (and step over) an
+ inline counter. */
#define BR_TAB_NAME "__BRANCH_TABLE__"
-/* Name of the table of pointers to branches.
- * A local (i.e., non-external) symbol.
- */
+/* Name of the table of pointers to branches. A local (i.e.,
+ non-external) symbol. */
\f
/*****************************************************************************
- * md_begin: One-time initialization.
- *
- * Set up hash tables.
- *
- **************************************************************************** */
+ md_begin: One-time initialization.
+
+ Set up hash tables.
+
+ *************************************************************************** */
void
md_begin ()
{
int i; /* Loop counter */
const struct i960_opcode *oP; /* Pointer into opcode table */
- char *retval; /* Value returned by hash functions */
+ const char *retval; /* Value returned by hash functions */
- if (((op_hash = hash_new ()) == 0)
- || ((reg_hash = hash_new ()) == 0)
- || ((areg_hash = hash_new ()) == 0))
- {
- as_fatal ("virtual memory exceeded");
- }
+ op_hash = hash_new ();
+ reg_hash = hash_new ();
+ areg_hash = hash_new ();
/* For some reason, the base assembler uses an empty string for "no
error message", instead of a NULL pointer. */
- retval = "";
+ retval = 0;
- for (oP = i960_opcodes; oP->name && !*retval; oP++)
- {
- retval = hash_insert (op_hash, oP->name, oP);
- }
-
- for (i = 0; regnames[i].reg_name && !*retval; i++)
- {
- retval = hash_insert (reg_hash, regnames[i].reg_name,
- ®names[i].reg_num);
- }
+ for (oP = i960_opcodes; oP->name && !retval; oP++)
+ retval = hash_insert (op_hash, oP->name, (PTR) oP);
- for (i = 0; aregs[i].areg_name && !*retval; i++)
- {
- retval = hash_insert (areg_hash, aregs[i].areg_name,
- &aregs[i].areg_num);
- }
+ for (i = 0; regnames[i].reg_name && !retval; i++)
+ retval = hash_insert (reg_hash, regnames[i].reg_name,
+ (char *) ®names[i].reg_num);
- if (*retval)
- {
- as_fatal ("Hashing returned \"%s\".", retval);
- }
-} /* md_begin() */
+ for (i = 0; aregs[i].areg_name && !retval; i++)
+ retval = hash_insert (areg_hash, aregs[i].areg_name,
+ (char *) &aregs[i].areg_num);
-/*****************************************************************************
- * md_end: One-time final cleanup
- *
- * None necessary
- *
- **************************************************************************** */
-void
-md_end ()
-{
+ if (retval)
+ as_fatal (_("Hashing returned \"%s\"."), retval);
}
/*****************************************************************************
- * md_assemble: Assemble an instruction
- *
- * Assumptions about the passed-in text:
- * - all comments, labels removed
- * - text is an instruction
- * - all white space compressed to single blanks
- * - all character constants have been replaced with decimal
- *
- **************************************************************************** */
+ md_assemble: Assemble an instruction
+
+ Assumptions about the passed-in text:
+ - all comments, labels removed
+ - text is an instruction
+ - all white space compressed to single blanks
+ - all character constants have been replaced with decimal
+
+ *************************************************************************** */
void
md_assemble (textP)
char *textP; /* Source text of instruction */
{
- /* Parsed instruction text, containing NO whitespace:
- * arg[0]->opcode mnemonic
- * arg[1-3]->operands, with char constants
- * replaced by decimal numbers
- */
+ /* Parsed instruction text, containing NO whitespace: arg[0]->opcode
+ mnemonic arg[1-3]->operands, with char constants replaced by
+ decimal numbers. */
char *args[4];
int n_ops; /* Number of instruction operands */
- int callx;
/* Pointer to instruction description */
struct i960_opcode *oP;
- /* TRUE iff opcode mnemonic included branch-prediction
- * suffix (".f" or ".t")
- */
+ /* TRUE iff opcode mnemonic included branch-prediction suffix (".f"
+ or ".t"). */
int branch_predict;
- /* Setting of branch-prediction bit(s) to be OR'd
- * into instruction opcode of CTRL/COBR format
- * instructions.
- */
+ /* Setting of branch-prediction bit(s) to be OR'd into instruction
+ opcode of CTRL/COBR format instructions. */
long bp_bits;
int n; /* Offset of last character in opcode mnemonic */
- static const char bp_error_msg[] = "branch prediction invalid on this opcode";
+ const char *bp_error_msg = _("branch prediction invalid on this opcode");
/* Parse instruction into opcode and operands */
if (args[0][n - 1] == '.' && (args[0][n] == 't' || args[0][n] == 'f'))
{
/* We could check here to see if the target architecture
- * supports branch prediction, but why bother? The bit
- * will just be ignored by processors that don't use it.
- */
+ supports branch prediction, but why bother? The bit will
+ just be ignored by processors that don't use it. */
branch_predict = 1;
bp_bits = (args[0][n] == 't') ? BP_TAKEN : BP_NOT_TAKEN;
args[0][n - 1] = '\0'; /* Strip suffix from opcode mnemonic */
}
/* Look up opcode mnemonic in table and check number of operands.
- * Check that opcode is legal for the target architecture.
- * If all looks good, assemble instruction.
- */
+ Check that opcode is legal for the target architecture. If all
+ looks good, assemble instruction. */
oP = (struct i960_opcode *) hash_find (op_hash, args[0]);
if (!oP || !targ_has_iclass (oP->iclass))
{
- as_bad ("invalid opcode, \"%s\".", args[0]);
+ as_bad (_("invalid opcode, \"%s\"."), args[0]);
}
else if (n_ops != oP->num_ops)
{
- as_bad ("improper number of operands. expecting %d, got %d",
+ as_bad (_("improper number of operands. expecting %d, got %d"),
oP->num_ops, n_ops);
}
else
{
as_warn (bp_error_msg);
}
- /* Output opcode & set up "fixup" (relocation);
- * flag relocation as 'callj' type.
- */
+ /* Output opcode & set up "fixup" (relocation); flag
+ relocation as 'callj' type. */
know (oP->num_ops == 1);
get_cdisp (args[1], "CTRL", oP->opcode, 24, 0, 1);
break;
} /* md_assemble() */
/*****************************************************************************
- * md_number_to_chars: convert a number to target byte order
- *
- **************************************************************************** */
+ md_number_to_chars: convert a number to target byte order
+
+ *************************************************************************** */
void
md_number_to_chars (buf, value, n)
- char *buf; /* Put output here */
- valueT value; /* The integer to be converted */
- int n; /* Number of bytes to output (significant bytes
- * in 'value')
- */
+ char *buf;
+ valueT value;
+ int n;
{
- while (n--)
- {
- *buf++ = value;
- value >>= 8;
- }
-
- /* XXX line number probably botched for this warning message. */
- if (value != 0 && value != -1)
- {
- as_bad ("Displacement too long for instruction field length.");
- }
-
- return;
-} /* md_number_to_chars() */
+ number_to_chars_littleendian (buf, value, n);
+}
/*****************************************************************************
- * md_chars_to_number: convert from target byte order to host byte order.
- *
- **************************************************************************** */
+ md_chars_to_number: convert from target byte order to host byte order.
+
+ *************************************************************************** */
int
md_chars_to_number (val, n)
unsigned char *val; /* Value in target byte order */
#define LNUM_SIZE sizeof(LITTLENUM_TYPE)
/*****************************************************************************
- * md_atof: convert ascii to floating point
- *
- * Turn a string at input_line_pointer into a floating point constant of type
- * 'type', and store the appropriate bytes at *litP. The number of LITTLENUMS
- * emitted is returned at 'sizeP'. An error message is returned, or a pointer
- * to an empty message if OK.
- *
- * Note we call the i386 floating point routine, rather than complicating
- * things with more files or symbolic links.
- *
- **************************************************************************** */
+ md_atof: convert ascii to floating point
+
+ Turn a string at input_line_pointer into a floating point constant of type
+ 'type', and store the appropriate bytes at *litP. The number of LITTLENUMS
+ emitted is returned at 'sizeP'. An error message is returned, or a pointer
+ to an empty message if OK.
+
+ Note we call the i386 floating point routine, rather than complicating
+ things with more files or symbolic links.
+
+ *************************************************************************** */
char *
md_atof (type, litP, sizeP)
int type;
default:
*sizeP = 0;
- return "Bad call to md_atof()";
+ return _("Bad call to md_atof()");
}
t = atof_ieee (input_line_pointer, type, words);
*sizeP = prec * LNUM_SIZE;
/* Output the LITTLENUMs in REVERSE order in accord with i80960
- * word-order. (Dunno why atof_ieee doesn't do it in the right
- * order in the first place -- probably because it's a hack of
- * atof_m68k.)
- */
+ word-order. (Dunno why atof_ieee doesn't do it in the right
+ order in the first place -- probably because it's a hack of
+ atof_m68k.) */
for (wordP = words + prec - 1; prec--;)
{
litP += sizeof (LITTLENUM_TYPE);
}
- return ""; /* Someone should teach Dean about null pointers */
+ return 0;
}
/*****************************************************************************
- * md_number_to_imm
- *
- **************************************************************************** */
+ md_number_to_imm
+
+ *************************************************************************** */
void
md_number_to_imm (buf, val, n)
char *buf;
/*****************************************************************************
- * md_number_to_disp
- *
- **************************************************************************** */
+ md_number_to_disp
+
+ *************************************************************************** */
void
md_number_to_disp (buf, val, n)
char *buf;
}
/*****************************************************************************
- * md_number_to_field:
- *
- * Stick a value (an address fixup) into a bit field of
- * previously-generated instruction.
- *
- **************************************************************************** */
+ md_number_to_field:
+
+ Stick a value (an address fixup) into a bit field of
+ previously-generated instruction.
+
+ *************************************************************************** */
void
md_number_to_field (instrP, val, bfixP)
char *instrP; /* Pointer to instruction to be fixed */
long instr; /* 32-bit instruction to be fixed-up */
long sign; /* 0 or -1, according to sign bit of 'val' */
- /* Convert instruction back to host byte order
- */
+ /* Convert instruction back to host byte order. */
instr = md_chars_to_number (instrP, 4);
- /* Surprise! -- we stored the number of bits
- * to be modified rather than a pointer to a structure.
- */
+ /* Surprise! -- we stored the number of bits to be modified rather
+ than a pointer to a structure. */
numbits = (int) bfixP;
if (numbits == 1)
{
know ((numbits == 13) || (numbits == 24));
- /* Propagate sign bit of 'val' for the given number of bits.
- * Result should be all 0 or all 1
- */
+ /* Propagate sign bit of 'val' for the given number of bits. Result
+ should be all 0 or all 1. */
sign = val >> ((int) numbits - 1);
if (((val < 0) && (sign != -1))
|| ((val > 0) && (sign != 0)))
{
- as_bad ("Fixup of %d too large for field width of %d",
+ as_bad (_("Fixup of %ld too large for field width of %d"),
val, numbits);
}
else
{
/* Put bit field into instruction and write back in target
- * byte order.
- */
+ * byte order.
+ */
val &= ~(-1 << (int) numbits); /* Clear unused sign bits */
instr |= val;
md_number_to_chars (instrP, instr, 4);
}
} /* md_number_to_field() */
-
+\f
/*****************************************************************************
- * md_parse_option
- * Invocation line includes a switch not recognized by the base assembler.
- * See if it's a processor-specific option. For the 960, these are:
- *
- * -norelax:
- * Conditional branch instructions that require displacements
- * greater than 13 bits (or that have external targets) should
- * generate errors. The default is to replace each such
- * instruction with the corresponding compare (or chkbit) and
- * branch instructions. Note that the Intel "j" cobr directives
- * are ALWAYS "de-optimized" in this way when necessary,
- * regardless of the setting of this option.
- *
- * -b:
- * Add code to collect information about branches taken, for
- * later optimization of branch prediction bits by a separate
- * tool. COBR and CNTL format instructions have branch
- * prediction bits (in the CX architecture); if "BR" represents
- * an instruction in one of these classes, the following rep-
- * resents the code generated by the assembler:
- *
- * call <increment routine>
- * .word 0 # pre-counter
- * Label: BR
- * call <increment routine>
- * .word 0 # post-counter
- *
- * A table of all such "Labels" is also generated.
- *
- *
- * -AKA, -AKB, -AKC, -ASA, -ASB, -AMC, -ACA:
- * Select the 80960 architecture. Instructions or features not
- * supported by the selected architecture cause fatal errors.
- * The default is to generate code for any instruction or feature
- * that is supported by SOME version of the 960 (even if this
- * means mixing architectures!).
- *
- **************************************************************************** */
-int
-md_parse_option (argP, cntP, vecP)
- char **argP;
- int *cntP;
- char ***vecP;
-{
- char *p;
- struct tabentry
- {
- char *flag;
- int arch;
- };
- static struct tabentry arch_tab[] =
+ md_parse_option
+ Invocation line includes a switch not recognized by the base assembler.
+ See if it's a processor-specific option. For the 960, these are:
+
+ -norelax:
+ Conditional branch instructions that require displacements
+ greater than 13 bits (or that have external targets) should
+ generate errors. The default is to replace each such
+ instruction with the corresponding compare (or chkbit) and
+ branch instructions. Note that the Intel "j" cobr directives
+ are ALWAYS "de-optimized" in this way when necessary,
+ regardless of the setting of this option.
+
+ -b:
+ Add code to collect information about branches taken, for
+ later optimization of branch prediction bits by a separate
+ tool. COBR and CNTL format instructions have branch
+ prediction bits (in the CX architecture); if "BR" represents
+ an instruction in one of these classes, the following rep-
+ resents the code generated by the assembler:
+
+ call <increment routine>
+ .word 0 # pre-counter
+ Label: BR
+ call <increment routine>
+ .word 0 # post-counter
+
+ A table of all such "Labels" is also generated.
+
+
+ -AKA, -AKB, -AKC, -ASA, -ASB, -AMC, -ACA:
+ Select the 80960 architecture. Instructions or features not
+ supported by the selected architecture cause fatal errors.
+ The default is to generate code for any instruction or feature
+ that is supported by SOME version of the 960 (even if this
+ means mixing architectures!).
+
+ ****************************************************************************/
+
+CONST char *md_shortopts = "A:b";
+struct option md_longopts[] =
+{
+#define OPTION_LINKRELAX (OPTION_MD_BASE)
+ {"linkrelax", no_argument, NULL, OPTION_LINKRELAX},
+ {"link-relax", no_argument, NULL, OPTION_LINKRELAX},
+#define OPTION_NORELAX (OPTION_MD_BASE + 1)
+ {"norelax", no_argument, NULL, OPTION_NORELAX},
+ {"no-relax", no_argument, NULL, OPTION_NORELAX},
+ {NULL, no_argument, NULL, 0}
+};
+size_t md_longopts_size = sizeof (md_longopts);
+
+struct tabentry
{
- "KA", ARCH_KA,
- "KB", ARCH_KB,
- "SA", ARCH_KA, /* Synonym for KA */
- "SB", ARCH_KB, /* Synonym for KB */
- "KC", ARCH_MC, /* Synonym for MC */
- "MC", ARCH_MC,
- "CA", ARCH_CA,
- NULL, 0
+ char *flag;
+ int arch;
};
- struct tabentry *tp;
- if (!strcmp (*argP, "linkrelax"))
+static const struct tabentry arch_tab[] =
+{
+ {"KA", ARCH_KA},
+ {"KB", ARCH_KB},
+ {"SA", ARCH_KA}, /* Synonym for KA */
+ {"SB", ARCH_KB}, /* Synonym for KB */
+ {"KC", ARCH_MC}, /* Synonym for MC */
+ {"MC", ARCH_MC},
+ {"CA", ARCH_CA},
+ {"JX", ARCH_JX},
+ {"HX", ARCH_HX},
+ {NULL, 0}
+};
+
+int
+md_parse_option (c, arg)
+ int c;
+ char *arg;
+{
+ switch (c)
{
+ case OPTION_LINKRELAX:
linkrelax = 1;
- flagseen['L'] = 1;
- }
- else if (!strcmp (*argP, "norelax"))
- {
+ flag_keep_locals = 1;
+ break;
+
+ case OPTION_NORELAX:
norelax = 1;
+ break;
- }
- else if (**argP == 'b')
- {
+ case 'b':
instrument_branches = 1;
+ break;
- }
- else if (**argP == 'A')
- {
- p = (*argP) + 1;
+ case 'A':
+ {
+ const struct tabentry *tp;
+ char *p = arg;
- for (tp = arch_tab; tp->flag != NULL; tp++)
- {
+ for (tp = arch_tab; tp->flag != NULL; tp++)
if (!strcmp (p, tp->flag))
- {
- break;
- }
- }
-
- if (tp->flag == NULL)
- {
- as_bad ("unknown architecture: %s", p);
- }
- else
- {
+ break;
+
+ if (tp->flag == NULL)
+ {
+ as_bad (_("invalid architecture %s"), p);
+ return 0;
+ }
+ else
architecture = tp->arch;
- }
- }
- else
- {
- /* Unknown option */
- (*argP)++;
+ }
+ break;
+
+ default:
return 0;
}
- **argP = '\0'; /* Done parsing this switch */
+
return 1;
}
+void
+md_show_usage (stream)
+ FILE *stream;
+{
+ int i;
+ fprintf (stream, _("I960 options:\n"));
+ for (i = 0; arch_tab[i].flag; i++)
+ fprintf (stream, "%s-A%s", i ? " | " : "", arch_tab[i].flag);
+ fprintf (stream, _("\n\
+ specify variant of 960 architecture\n\
+-b add code to collect statistics about branches taken\n\
+-link-relax preserve individual alignment directives so linker\n\
+ can do relaxing (b.out format only)\n\
+-no-relax don't alter compare-and-branch instructions for\n\
+ long displacements\n"));
+}
+\f
+
/*****************************************************************************
- * md_convert_frag:
- * Called by base assembler after address relaxation is finished: modify
- * variable fragments according to how much relaxation was done.
- *
- * If the fragment substate is still 1, a 13-bit displacement was enough
- * to reach the symbol in question. Set up an address fixup, but otherwise
- * leave the cobr instruction alone.
- *
- * If the fragment substate is 2, a 13-bit displacement was not enough.
- * Replace the cobr with a two instructions (a compare and a branch).
- *
- **************************************************************************** */
+ md_convert_frag:
+ Called by base assembler after address relaxation is finished: modify
+ variable fragments according to how much relaxation was done.
+
+ If the fragment substate is still 1, a 13-bit displacement was enough
+ to reach the symbol in question. Set up an address fixup, but otherwise
+ leave the cobr instruction alone.
+
+ If the fragment substate is 2, a 13-bit displacement was not enough.
+ Replace the cobr with a two instructions (a compare and a branch).
+
+ *************************************************************************** */
+#ifndef BFD_ASSEMBLER
void
-md_convert_frag (headers, fragP)
+md_convert_frag (headers, seg, fragP)
object_headers *headers;
+ segT seg;
fragS *fragP;
+#else
+void
+md_convert_frag (abfd, sec, fragP)
+ bfd *abfd;
+ segT sec;
+ fragS *fragP;
+#endif
{
fixS *fixP; /* Structure describing needed address fix */
}
/*****************************************************************************
- * md_estimate_size_before_relax: How much does it look like *fragP will grow?
- *
- * Called by base assembler just before address relaxation.
- * Return the amount by which the fragment will grow.
- *
- * Any symbol that is now undefined will not become defined; cobr's
- * based on undefined symbols will have to be replaced with a compare
- * instruction and a branch instruction, and the code fragment will grow
- * by 4 bytes.
- *
- **************************************************************************** */
+ md_estimate_size_before_relax: How much does it look like *fragP will grow?
+
+ Called by base assembler just before address relaxation.
+ Return the amount by which the fragment will grow.
+
+ Any symbol that is now undefined will not become defined; cobr's
+ based on undefined symbols will have to be replaced with a compare
+ instruction and a branch instruction, and the code fragment will grow
+ by 4 bytes.
+
+ *************************************************************************** */
int
md_estimate_size_before_relax (fragP, segment_type)
register fragS *fragP;
register segT segment_type;
{
/* If symbol is undefined in this segment, go to "relaxed" state
- * (compare and branch instructions instead of cobr) right now.
- */
+ (compare and branch instructions instead of cobr) right now. */
if (S_GET_SEGMENT (fragP->fr_symbol) != segment_type)
{
relax_cobr (fragP);
return 0;
} /* md_estimate_size_before_relax() */
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
/*****************************************************************************
- * md_ri_to_chars:
- * This routine exists in order to overcome machine byte-order problems
- * when dealing with bit-field entries in the relocation_info struct.
- *
- * But relocation info will be used on the host machine only (only
- * executable code is actually downloaded to the i80960). Therefore,
- * we leave it in host byte order.
- *
- * The above comment is no longer true. This routine now really
- * does do the reordering (Ian Taylor 28 Aug 92).
- *
- **************************************************************************** */
-void
+ md_ri_to_chars:
+ This routine exists in order to overcome machine byte-order problems
+ when dealing with bit-field entries in the relocation_info struct.
+
+ But relocation info will be used on the host machine only (only
+ executable code is actually downloaded to the i80960). Therefore,
+ we leave it in host byte order.
+
+ The above comment is no longer true. This routine now really
+ does do the reordering (Ian Taylor 28 Aug 92).
+
+ *************************************************************************** */
+
+static void
md_ri_to_chars (where, ri)
char *where;
struct relocation_info *ri;
| (ri->r_bsr << 4)
| (ri->r_disp << 5)
| (ri->r_callj << 6));
-} /* md_ri_to_chars() */
-
-#ifndef WORKING_DOT_WORD
-
-int md_short_jump_size = 0;
-int md_long_jump_size = 0;
-
-void
-md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
- char *ptr;
- addressT from_addr;
- addressT to_addr;
- fragS *frag;
- symbolS *to_symbol;
-{
- as_fatal ("failed sanity check.");
}
-void
-md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
- char *ptr;
- addressT from_addr, to_addr;
- fragS *frag;
- symbolS *to_symbol;
-{
- as_fatal ("failed sanity check.");
-}
+#endif /* defined(OBJ_AOUT) | defined(OBJ_BOUT) */
-#endif
\f
-/*************************************************************
- * *
- * FOLLOWING ARE THE LOCAL ROUTINES, IN ALPHABETICAL ORDER *
- * *
- ************************************************************ */
-
-
+/* FOLLOWING ARE THE LOCAL ROUTINES, IN ALPHABETICAL ORDER */
/*****************************************************************************
- * brcnt_emit: Emit code to increment inline branch counter.
- *
- * See the comments above the declaration of 'br_cnt' for details on
- * branch-prediction instrumentation.
- **************************************************************************** */
+ brcnt_emit: Emit code to increment inline branch counter.
+
+ See the comments above the declaration of 'br_cnt' for details on
+ branch-prediction instrumentation.
+ *************************************************************************** */
static void
brcnt_emit ()
{
}
/*****************************************************************************
- * brlab_next: generate the next branch local label
- *
- * See the comments above the declaration of 'br_cnt' for details on
- * branch-prediction instrumentation.
- **************************************************************************** */
+ brlab_next: generate the next branch local label
+
+ See the comments above the declaration of 'br_cnt' for details on
+ branch-prediction instrumentation.
+ *************************************************************************** */
static char *
brlab_next ()
{
}
/*****************************************************************************
- * brtab_emit: generate the fetch-prediction branch table.
- *
- * See the comments above the declaration of 'br_cnt' for details on
- * branch-prediction instrumentation.
- *
- * The code emitted here would be functionally equivalent to the following
- * example assembler source.
- *
- * .data
- * .align 2
- * BR_TAB_NAME:
- * .word 0 # link to next table
- * .word 3 # length of table
- * .word LBRANCH0 # 1st entry in table proper
- * .word LBRANCH1
- * .word LBRANCH2
- ***************************************************************************** */
+ brtab_emit: generate the fetch-prediction branch table.
+
+ See the comments above the declaration of 'br_cnt' for details on
+ branch-prediction instrumentation.
+
+ The code emitted here would be functionally equivalent to the following
+ example assembler source.
+
+ .data
+ .align 2
+ BR_TAB_NAME:
+ .word 0 # link to next table
+ .word 3 # length of table
+ .word LBRANCH0 # 1st entry in table proper
+ .word LBRANCH1
+ .word LBRANCH2
+ **************************************************************************** */
void
brtab_emit ()
{
int i;
char buf[20];
char *p; /* Where the binary was output to */
- fixS *fixP; /*->description of deferred address fixup */
+ /* Pointer to description of deferred address fixup. */
+ fixS *fixP;
if (!instrument_branches)
{
return;
}
- subseg_set (SEG_DATA, 0); /* .data */
- frag_align (2, 0); /* .align 2 */
+ subseg_set (data_section, 0); /* .data */
+ frag_align (2, 0, 0); /* .align 2 */
record_alignment (now_seg, 2);
colon (BR_TAB_NAME); /* BR_TAB_NAME: */
- emit (0); /* .word 0 #link to next table */
- emit (br_cnt); /* .word n #length of table */
+ emit (0); /* .word 0 #link to next table */
+ emit (br_cnt); /* .word n #length of table */
for (i = 0; i < br_cnt; i++)
{
0,
0,
NO_RELOC);
- fixP->fx_im_disp = 2; /* 32-bit displacement fix */
}
}
/*****************************************************************************
- * cobr_fmt: generate a COBR-format instruction
- *
- **************************************************************************** */
+ cobr_fmt: generate a COBR-format instruction
+
+ *************************************************************************** */
static
void
cobr_fmt (arg, opcode, oP)
- char *arg[]; /* arg[0]->opcode mnemonic, arg[1-3]->operands (ascii) */
- long opcode; /* Opcode, with branch-prediction bits already set
- * if necessary.
- */
+ /* arg[0]->opcode mnemonic, arg[1-3]->operands (ascii) */
+ char *arg[];
+ /* Opcode, with branch-prediction bits already set if necessary. */
+ long opcode;
+ /* Pointer to description of instruction. */
struct i960_opcode *oP;
- /*->description of instruction */
{
long instr; /* 32-bit instruction */
struct regop regop; /* Description of register operand */
int n; /* Number of operands */
int var_frag; /* 1 if varying length code fragment should
- * be emitted; 0 if an address fix
- * should be emitted.
+ * be emitted; 0 if an address fix
+ * should be emitted.
*/
instr = opcode;
if (n >= 1)
{
/* First operand (if any) of a COBR is always a register
- * operand. Parse it.
- */
+ operand. Parse it. */
parse_regop (®op, arg[1], oP->operand[0]);
instr |= (regop.n << 19) | (regop.mode << 13);
}
if (n >= 2)
{
/* Second operand (if any) of a COBR is always a register
- * operand. Parse it.
- */
- parse_regop (®op, arg[2], oP->operand[1]);
+ operand. Parse it. */
+ parse_regop (®op, arg[2], oP->operand[1]);
instr |= (regop.n << 14) | regop.special;
}
colon (brlab_next ());
}
- /* A third operand to a COBR is always a displacement.
- * Parse it; if it's relaxable (a cobr "j" directive, or any
- * cobr other than bbs/bbc when the "-norelax" option is not in
- * use) set up a variable code fragment; otherwise set up an
- * address fix.
- */
+ /* A third operand to a COBR is always a displacement. Parse
+ it; if it's relaxable (a cobr "j" directive, or any cobr
+ other than bbs/bbc when the "-norelax" option is not in use)
+ set up a variable code fragment; otherwise set up an address
+ fix. */
var_frag = !norelax || (oP->format == COJ); /* TRUE or FALSE */
get_cdisp (arg[3], "COBR", instr, 13, var_frag, 0);
/*****************************************************************************
- * ctrl_fmt: generate a CTRL-format instruction
- *
- **************************************************************************** */
+ ctrl_fmt: generate a CTRL-format instruction
+
+ *************************************************************************** */
static
void
ctrl_fmt (targP, opcode, num_ops)
int num_ops; /* Number of operands */
{
int instrument; /* TRUE iff we should add instrumentation to track
- * how often the branch is taken
- */
+ * how often the branch is taken
+ */
if (num_ops == 0)
}
/* The operand MUST be an ip-relative displacment. Parse it
- * and set up address fix for the instruction we just output.
- */
+ * and set up address fix for the instruction we just output.
+ */
get_cdisp (targP, "CTRL", opcode, 24, 0, 0);
if (instrument)
/*****************************************************************************
- * emit: output instruction binary
- *
- * Output instruction binary, in target byte order, 4 bytes at a time.
- * Return pointer to where it was placed.
- *
- **************************************************************************** */
+ emit: output instruction binary
+
+ Output instruction binary, in target byte order, 4 bytes at a time.
+ Return pointer to where it was placed.
+
+ *************************************************************************** */
static
char *
emit (instr)
/*****************************************************************************
- * get_args: break individual arguments out of comma-separated list
- *
- * Input assumptions:
- * - all comments and labels have been removed
- * - all strings of whitespace have been collapsed to a single blank.
- * - all character constants ('x') have been replaced with decimal
- *
- * Output:
- * args[0] is untouched. args[1] points to first operand, etc. All args:
- * - are NULL-terminated
- * - contain no whitespace
- *
- * Return value:
- * Number of operands (0,1,2, or 3) or -1 on error.
- *
- **************************************************************************** */
+ get_args: break individual arguments out of comma-separated list
+
+ Input assumptions:
+ - all comments and labels have been removed
+ - all strings of whitespace have been collapsed to a single blank.
+ - all character constants ('x') have been replaced with decimal
+
+ Output:
+ args[0] is untouched. args[1] points to first operand, etc. All args:
+ - are NULL-terminated
+ - contain no whitespace
+
+ Return value:
+ Number of operands (0,1,2, or 3) or -1 on error.
+
+ *************************************************************************** */
static int
get_args (p, args)
- register char *p; /* Pointer to comma-separated operands; MUCKED BY US */
- char *args[]; /* Output arg: pointers to operands placed in args[1-3].
- * MUST ACCOMMODATE 4 ENTRIES (args[0-3]).
- */
+ /* Pointer to comma-separated operands; MUCKED BY US */
+ register char *p;
+ /* Output arg: pointers to operands placed in args[1-3]. MUST
+ ACCOMMODATE 4 ENTRIES (args[0-3]). */
+ char *args[];
{
register int n; /* Number of operands */
register char *to;
- /* char buf[4]; */
- /* int len; */
-
/* Skip lead white space */
while (*p == ' ')
args[1] = p;
/* Squeze blanks out by moving non-blanks toward start of string.
- * Isolate operands, whenever comma is found.
- */
+ * Isolate operands, whenever comma is found.
+ */
to = p;
while (*p != '\0')
{
- if (*p == ' ')
+ if (*p == ' '
+ && (! isalnum ((unsigned char) p[1])
+ || ! isalnum ((unsigned char) p[-1])))
{
p++;
/* Start of operand */
if (n == 3)
{
- as_bad ("too many operands");
+ as_bad (_("too many operands"));
return -1;
}
*to++ = '\0'; /* Terminate argument */
/*****************************************************************************
- * get_cdisp: handle displacement for a COBR or CTRL instruction.
- *
- * Parse displacement for a COBR or CTRL instruction.
- *
- * If successful, output the instruction opcode and set up for it,
- * depending on the arg 'var_frag', either:
- * o an address fixup to be done when all symbol values are known, or
- * o a varying length code fragment, with address fixup info. This
- * will be done for cobr instructions that may have to be relaxed
- * in to compare/branch instructions (8 bytes) if the final
- * address displacement is greater than 13 bits.
- *
- *****************************************************************************/
+ get_cdisp: handle displacement for a COBR or CTRL instruction.
+
+ Parse displacement for a COBR or CTRL instruction.
+
+ If successful, output the instruction opcode and set up for it,
+ depending on the arg 'var_frag', either:
+ o an address fixup to be done when all symbol values are known, or
+ o a varying length code fragment, with address fixup info. This
+ will be done for cobr instructions that may have to be relaxed
+ in to compare/branch instructions (8 bytes) if the final
+ address displacement is greater than 13 bits.
+
+ ****************************************************************************/
static
void
get_cdisp (dispP, ifmtP, instr, numbits, var_frag, callj)
/* # bits of displacement (13 for COBR, 24 for CTRL) */
int numbits;
/* 1 if varying length code fragment should be emitted;
- * 0 if an address fix should be emitted.
+ * 0 if an address fix should be emitted.
*/
int var_frag;
/* 1 if callj relocation should be done; else 0 */
switch (e.X_op)
{
case O_illegal:
- as_bad ("expression syntax error");
+ as_bad (_("expression syntax error"));
case O_symbol:
- if (S_GET_SEGMENT (e.X_add_symbol) == text_section
+ if (S_GET_SEGMENT (e.X_add_symbol) == now_seg
|| S_GET_SEGMENT (e.X_add_symbol) == undefined_section)
- {
+ {
if (var_frag)
{
- outP = frag_more (8); /* Allocate worst-case storage */
+ outP = frag_more (8); /* Allocate worst-case storage */
md_number_to_chars (outP, instr, 4);
frag_variant (rs_machine_dependent, 4, 4, 1,
- adds (e), offs (e), outP, 0, 0);
+ adds (e), offs (e), outP);
}
else
{
1,
NO_RELOC);
- fixP->fx_callj = callj;
+ fixP->fx_tcbit = callj;
/* We want to modify a bit field when the address is
* known. But we don't need all the garbage in the
}
}
else
- as_bad ("attempt to branch into different segment");
+ as_bad (_("attempt to branch into different segment"));
break;
default:
- as_bad ("target of %s instruction must be a label", ifmtP);
+ as_bad (_("target of %s instruction must be a label"), ifmtP);
break;
}
}
/*****************************************************************************
- * get_ispec: parse a memory operand for an index specification
- *
- * Here, an "index specification" is taken to be anything surrounded
- * by square brackets and NOT followed by anything else.
- *
- * If it's found, detach it from the input string, remove the surrounding
- * square brackets, and return a pointer to it. Otherwise, return NULL.
- *
- **************************************************************************** */
+ get_ispec: parse a memory operand for an index specification
+
+ Here, an "index specification" is taken to be anything surrounded
+ by square brackets and NOT followed by anything else.
+
+ If it's found, detach it from the input string, remove the surrounding
+ square brackets, and return a pointer to it. Otherwise, return NULL.
+
+ *************************************************************************** */
static
char *
get_ispec (textP)
- char *textP; /*->memory operand from source instruction, no white space */
+ /* Pointer to memory operand from source instruction, no white space. */
+ char *textP;
{
- char *start; /*->start of index specification */
- char *end; /*->end of index specification */
+ /* Points to start of index specification. */
+ char *start;
+ /* Points to end of index specification. */
+ char *end;
- /* Find opening square bracket, if any
- */
+ /* Find opening square bracket, if any. */
start = strchr (textP, '[');
if (start != NULL)
if (end == NULL)
{
- as_bad ("unmatched '['");
+ as_bad (_("unmatched '['"));
}
else
{
/* Eliminate ']' and make sure it was the last thing
- * in the string.
- */
+ * in the string.
+ */
*end = '\0';
if (*(end + 1) != '\0')
{
- as_bad ("garbage after index spec ignored");
+ as_bad (_("garbage after index spec ignored"));
}
}
}
}
/*****************************************************************************
- * get_regnum:
- *
- * Look up a (suspected) register name in the register table and return the
- * associated register number (or -1 if not found).
- *
- **************************************************************************** */
+ get_regnum:
+
+ Look up a (suspected) register name in the register table and return the
+ associated register number (or -1 if not found).
+
+ *************************************************************************** */
static
int
get_regnum (regname)
/*****************************************************************************
- * i_scan: perform lexical scan of ascii assembler instruction.
- *
- * Input assumptions:
- * - input string is an i80960 instruction (not a pseudo-op)
- * - all comments and labels have been removed
- * - all strings of whitespace have been collapsed to a single blank.
- *
- * Output:
- * args[0] points to opcode, other entries point to operands. All strings:
- * - are NULL-terminated
- * - contain no whitespace
- * - have character constants ('x') replaced with a decimal number
- *
- * Return value:
- * Number of operands (0,1,2, or 3) or -1 on error.
- *
- **************************************************************************** */
+ i_scan: perform lexical scan of ascii assembler instruction.
+
+ Input assumptions:
+ - input string is an i80960 instruction (not a pseudo-op)
+ - all comments and labels have been removed
+ - all strings of whitespace have been collapsed to a single blank.
+
+ Output:
+ args[0] points to opcode, other entries point to operands. All strings:
+ - are NULL-terminated
+ - contain no whitespace
+ - have character constants ('x') replaced with a decimal number
+
+ Return value:
+ Number of operands (0,1,2, or 3) or -1 on error.
+
+ *************************************************************************** */
static int
i_scan (iP, args)
- register char *iP; /* Pointer to ascii instruction; MUCKED BY US. */
- char *args[]; /* Output arg: pointers to opcode and operands placed
- * here. MUST ACCOMMODATE 4 ENTRIES.
- */
+ /* Pointer to ascii instruction; MUCKED BY US. */
+ register char *iP;
+ /* Output arg: pointers to opcode and operands placed here. MUST
+ ACCOMMODATE 4 ENTRIES. */
+ char *args[];
{
/* Isolate opcode */
if (args[0] == iP)
{
/* We never moved: there was no opcode either! */
- as_bad ("missing opcode");
+ as_bad (_("missing opcode"));
return -1;
}
return 0;
/*****************************************************************************
- * mem_fmt: generate a MEMA- or MEMB-format instruction
- *
- **************************************************************************** */
+ mem_fmt: generate a MEMA- or MEMB-format instruction
+
+ *************************************************************************** */
static void
mem_fmt (args, oP, callx)
char *args[]; /* args[0]->opcode mnemonic, args[1-3]->operands */
memS instr; /* Description of binary to be output */
char *outP; /* Where the binary was output to */
expressionS expr; /* Parsed expression */
- fixS *fixP; /*->description of deferred address fixup */
+ /* ->description of deferred address fixup */
+ fixS *fixP;
+
+#ifdef OBJ_COFF
+ /* COFF support isn't in place yet for callx relaxing. */
+ callx = 0;
+#endif
memset (&instr, '\0', sizeof (memS));
instr.opcode = oP->opcode;
}
}
+ /* Parse the displacement; this must be done before emitting the
+ opcode, in case it is an expression using `.'. */
+ parse_expr (instr.e, &expr);
+
/* Output opcode */
outP = emit (instr.opcode);
return;
}
- /* Parse and process the displacement */
- parse_expr (instr.e, &expr);
+ /* Process the displacement */
switch (expr.X_op)
{
case O_illegal:
- as_bad ("expression syntax error");
+ as_bad (_("expression syntax error"));
break;
case O_constant:
&expr,
0,
NO_RELOC);
- fixP->fx_im_disp = 2; /* 32-bit displacement fix */
- fixP->fx_bsr = callx; /*SAC LD RELAX HACK *//* Mark reloc as being in i stream */
+ /* Steve's linker relaxing hack. Mark this 32-bit relocation as
+ being in the instruction stream, specifically as part of a callx
+ instruction. */
+ fixP->fx_bsr = callx;
break;
}
} /* memfmt() */
/*****************************************************************************
- * mema_to_memb: convert a MEMA-format opcode to a MEMB-format opcode.
- *
- * There are 2 possible MEMA formats:
- * - displacement only
- * - displacement + abase
- *
- * They are distinguished by the setting of the MEMA_ABASE bit.
- *
- **************************************************************************** */
+ mema_to_memb: convert a MEMA-format opcode to a MEMB-format opcode.
+
+ There are 2 possible MEMA formats:
+ - displacement only
+ - displacement + abase
+
+ They are distinguished by the setting of the MEMA_ABASE bit.
+
+ *************************************************************************** */
static void
mema_to_memb (opcodeP)
char *opcodeP; /* Where to find the opcode, in target byte order */
/*****************************************************************************
- * parse_expr: parse an expression
- *
- * Use base assembler's expression parser to parse an expression.
- * It, unfortunately, runs off a global which we have to save/restore
- * in order to make it work for us.
- *
- * An empty expression string is treated as an absolute 0.
- *
- * Sets O_illegal regardless of expression evaluation if entire input
- * string is not consumed in the evaluation -- tolerate no dangling junk!
- *
- **************************************************************************** */
+ parse_expr: parse an expression
+
+ Use base assembler's expression parser to parse an expression.
+ It, unfortunately, runs off a global which we have to save/restore
+ in order to make it work for us.
+
+ An empty expression string is treated as an absolute 0.
+
+ Sets O_illegal regardless of expression evaluation if entire input
+ string is not consumed in the evaluation -- tolerate no dangling junk!
+
+ *************************************************************************** */
static void
parse_expr (textP, expP)
char *textP; /* Text of expression to be parsed */
input_line_pointer = textP; /* Make parser work for us */
(void) expression (expP);
- if (input_line_pointer - textP != strlen (textP))
+ if ((size_t) (input_line_pointer - textP) != strlen (textP))
{
/* Did not consume all of the input */
expP->X_op = O_illegal;
/*****************************************************************************
- * parse_ldcont:
- * Parse and replace a 'ldconst' pseudo-instruction with an appropriate
- * i80960 instruction.
- *
- * Assumes the input consists of:
- * arg[0] opcode mnemonic ('ldconst')
- * arg[1] first operand (constant)
- * arg[2] name of register to be loaded
- *
- * Replaces opcode and/or operands as appropriate.
- *
- * Returns the new number of arguments, or -1 on failure.
- *
- **************************************************************************** */
+ parse_ldcont:
+ Parse and replace a 'ldconst' pseudo-instruction with an appropriate
+ i80960 instruction.
+
+ Assumes the input consists of:
+ arg[0] opcode mnemonic ('ldconst')
+ arg[1] first operand (constant)
+ arg[2] name of register to be loaded
+
+ Replaces opcode and/or operands as appropriate.
+
+ Returns the new number of arguments, or -1 on failure.
+
+ *************************************************************************** */
static
int
parse_ldconst (arg)
case O_constant:
/* Try the following mappings:
- * ldconst 0,<reg> ->mov 0,<reg>
- * ldconst 31,<reg> ->mov 31,<reg>
- * ldconst 32,<reg> ->addo 1,31,<reg>
- * ldconst 62,<reg> ->addo 31,31,<reg>
- * ldconst 64,<reg> ->shlo 8,3,<reg>
- * ldconst -1,<reg> ->subo 1,0,<reg>
- * ldconst -31,<reg>->subo 31,0,<reg>
+ * ldconst 0,<reg> ->mov 0,<reg>
+ * ldconst 31,<reg> ->mov 31,<reg>
+ * ldconst 32,<reg> ->addo 1,31,<reg>
+ * ldconst 62,<reg> ->addo 31,31,<reg>
+ * ldconst 64,<reg> ->shlo 8,3,<reg>
+ * ldconst -1,<reg> ->subo 1,0,<reg>
+ * ldconst -31,<reg>->subo 31,0,<reg>
*
* anthing else becomes:
- * lda xxx,<reg>
+ * lda xxx,<reg>
*/
n = offs (e);
if ((0 <= n) && (n <= 31))
break;
case O_illegal:
- as_bad ("invalid constant");
+ as_bad (_("invalid constant"));
return -1;
break;
}
}
/*****************************************************************************
- * parse_memop: parse a memory operand
- *
- * This routine is based on the observation that the 4 mode bits of the
- * MEMB format, taken individually, have fairly consistent meaning:
- *
- * M3 (bit 13): 1 if displacement is present (D_BIT)
- * M2 (bit 12): 1 for MEMB instructions (MEMB_BIT)
- * M1 (bit 11): 1 if index is present (I_BIT)
- * M0 (bit 10): 1 if abase is present (A_BIT)
- *
- * So we parse the memory operand and set bits in the mode as we find
- * things. Then at the end, if we go to MEMB format, we need only set
- * the MEMB bit (M2) and our mode is built for us.
- *
- * Unfortunately, I said "fairly consistent". The exceptions:
- *
- * DBIA
- * 0100 Would seem illegal, but means "abase-only".
- *
- * 0101 Would seem to mean "abase-only" -- it means IP-relative.
- * Must be converted to 0100.
- *
- * 0110 Would seem to mean "index-only", but is reserved.
- * We turn on the D bit and provide a 0 displacement.
- *
- * The other thing to observe is that we parse from the right, peeling
- * things * off as we go: first any index spec, then any abase, then
- * the displacement.
- *
- **************************************************************************** */
+ parse_memop: parse a memory operand
+
+ This routine is based on the observation that the 4 mode bits of the
+ MEMB format, taken individually, have fairly consistent meaning:
+
+ M3 (bit 13): 1 if displacement is present (D_BIT)
+ M2 (bit 12): 1 for MEMB instructions (MEMB_BIT)
+ M1 (bit 11): 1 if index is present (I_BIT)
+ M0 (bit 10): 1 if abase is present (A_BIT)
+
+ So we parse the memory operand and set bits in the mode as we find
+ things. Then at the end, if we go to MEMB format, we need only set
+ the MEMB bit (M2) and our mode is built for us.
+
+ Unfortunately, I said "fairly consistent". The exceptions:
+
+ DBIA
+ 0100 Would seem illegal, but means "abase-only".
+
+ 0101 Would seem to mean "abase-only" -- it means IP-relative.
+ Must be converted to 0100.
+
+ 0110 Would seem to mean "index-only", but is reserved.
+ We turn on the D bit and provide a 0 displacement.
+
+ The other thing to observe is that we parse from the right, peeling
+ things * off as we go: first any index spec, then any abase, then
+ the displacement.
+
+ *************************************************************************** */
static
void
parse_memop (memP, argP, optype)
char *p; /* Temp char pointer */
char iprel_flag; /* True if this is an IP-relative operand */
int regnum; /* Register number */
- int scale; /* Scale factor: 1,2,4,8, or 16. Later converted
- * to internal format (0,1,2,3,4 respectively).
- */
+ /* Scale factor: 1,2,4,8, or 16. Later converted to internal format
+ (0,1,2,3,4 respectively). */
+ int scale;
int mode; /* MEMB mode bits */
int *intP; /* Pointer to register number */
/* The following table contains the default scale factors for each
- * type of memory instruction. It is accessed using (optype-MEM1)
- * as an index -- thus it assumes the 'optype' constants are assigned
- * consecutive values, in the order they appear in this table
- */
- static int def_scale[] =
+ type of memory instruction. It is accessed using (optype-MEM1)
+ as an index -- thus it assumes the 'optype' constants are
+ assigned consecutive values, in the order they appear in this
+ table. */
+ static const int def_scale[] =
{
1, /* MEM1 */
2, /* MEM2 */
p = strchr (indexP, '*');
if (p == NULL)
{
- /* No explicit scale -- use default for this
- *instruction type.
- */
- scale = def_scale[optype - MEM1];
+ /* No explicit scale -- use default for this instruction
+ type and assembler mode. */
+ if (flag_mri)
+ scale = 1;
+ else
+ /* GNU960 compatibility */
+ scale = def_scale[optype - MEM1];
}
else
{
*p++ = '\0'; /* Eliminate '*' */
/* Now indexP->a '\0'-terminated register name,
- * and p->a scale factor.
- */
+ * and p->a scale factor.
+ */
if (!strcmp (p, "16"))
{
regnum = get_regnum (indexP); /* Get index reg. # */
if (!IS_RG_REG (regnum))
{
- as_bad ("invalid index register");
+ as_bad (_("invalid index register"));
return;
}
scale = 4 << 7;
break;
default:
- as_bad ("invalid scale factor");
+ as_bad (_("invalid scale factor"));
return;
};
/* Any abase (Register Indirect) specification present? */
if ((p = strrchr (argP, '(')) != NULL)
{
- /* "(" is there -- does it start a legal abase spec?
- * (If not it could be part of a displacement expression.)
- */
+ /* "(" is there -- does it start a legal abase spec? If not, it
+ could be part of a displacement expression. */
intP = (int *) hash_find (areg_hash, p);
if (intP != NULL)
{
{
case D_BIT | A_BIT:
/* Go with MEMA instruction format for now (grow to MEMB later
- * if 12 bits is not enough for the displacement).
- * MEMA format has a single mode bit: set it to indicate
- * that abase is present.
- */
+ if 12 bits is not enough for the displacement). MEMA format
+ has a single mode bit: set it to indicate that abase is
+ present. */
memP->opcode |= MEMA_ABASE;
memP->disp = 12;
break;
case D_BIT:
/* Go with MEMA instruction format for now (grow to MEMB later
- * if 12 bits is not enough for the displacement).
- */
+ if 12 bits is not enough for the displacement). */
memP->disp = 12;
break;
case A_BIT:
/* For some reason, the bit string for this mode is not
- * consistent: it should be 0 (exclusive of the MEMB bit),
- * so we set it "by hand" here.
- */
+ consistent: it should be 0 (exclusive of the MEMB bit), so we
+ set it "by hand" here. */
memP->opcode |= MEMB_BIT;
break;
break;
case I_BIT:
- /* Treat missing displacement as displacement of 0 */
+ /* Treat missing displacement as displacement of 0. */
mode |= D_BIT;
- /***********************
- * Fall into next case *
- ********************** */
+ /* Fall into next case. */
case D_BIT | A_BIT | I_BIT:
case D_BIT | I_BIT:
/* set MEMB bit in mode, and OR in mode bits */
}
/*****************************************************************************
- * parse_po: parse machine-dependent pseudo-op
- *
- * This is a top-level routine for machine-dependent pseudo-ops. It slurps
- * up the rest of the input line, breaks out the individual arguments,
- * and dispatches them to the correct handler.
- **************************************************************************** */
+ parse_po: parse machine-dependent pseudo-op
+
+ This is a top-level routine for machine-dependent pseudo-ops. It slurps
+ up the rest of the input line, breaks out the individual arguments,
+ and dispatches them to the correct handler.
+ *************************************************************************** */
static
void
parse_po (po_num)
int po_num; /* Pseudo-op number: currently S_LEAFPROC or S_SYSPROC */
{
- char *args[4]; /* Pointers operands, with no embedded whitespace.
- * arg[0] unused.
- * arg[1-3]->operands
- */
+ /* Pointers operands, with no embedded whitespace.
+ arg[0] unused, arg[1-3]->operands */
+ char *args[4];
int n_ops; /* Number of operands */
char *p; /* Pointer to beginning of unparsed argument string */
char eol; /* Character that indicated end of line */
/* Advance input pointer to end of line. */
p = input_line_pointer;
- while (!is_end_of_line[*input_line_pointer])
+ while (!is_end_of_line[(unsigned char) *input_line_pointer])
{
input_line_pointer++;
}
break;
}
- /* Restore eol, so line numbers get updated correctly. Base assembler
- * assumes we leave input pointer pointing at char following the eol.
- */
+ /* Restore eol, so line numbers get updated correctly. Base
+ assembler assumes we leave input pointer pointing at char
+ following the eol. */
*input_line_pointer++ = eol;
}
/*****************************************************************************
- * parse_regop: parse a register operand.
- *
- * In case of illegal operand, issue a message and return some valid
- * information so instruction processing can continue.
- **************************************************************************** */
+ parse_regop: parse a register operand.
+
+ In case of illegal operand, issue a message and return some valid
+ information so instruction processing can continue.
+ *************************************************************************** */
static
void
parse_regop (regopP, optext, opdesc)
/* global or local register */
if (!REG_ALIGN (opdesc, n))
{
- as_bad ("unaligned register");
+ as_bad (_("unaligned register"));
}
regopP->n = n;
regopP->mode = 0;
regopP->special = 1;
if (!targ_has_sfr (regopP->n))
{
- as_bad ("no such sfr in this architecture");
+ as_bad (_("no such sfr in this architecture"));
}
return;
}
}
else if (LIT_OK (opdesc))
{
- /*
- * How about a literal?
- */
+ /* How about a literal? */
regopP->mode = 1;
regopP->special = 0;
if (FP_OK (opdesc))
if (e.X_op != O_constant
|| (offs (e) < 0) || (offs (e) > 31))
{
- as_bad ("illegal literal");
+ as_bad (_("illegal literal"));
offs (e) = 0;
}
regopP->n = offs (e);
} /* parse_regop() */
/*****************************************************************************
- * reg_fmt: generate a REG-format instruction
- *
- **************************************************************************** */
+ reg_fmt: generate a REG-format instruction
+
+ *************************************************************************** */
static void
reg_fmt (args, oP)
char *args[]; /* args[0]->opcode mnemonic, args[1-3]->operands */
if ((n_ops == 1) && !(instr & M3))
{
/* 1-operand instruction in which the dst field should
- * be used (instead of src1).
- */
+ * be used (instead of src1).
+ */
regop.n <<= 19;
if (regop.special)
{
if ((n_ops == 2) && !(instr & M3))
{
/* 2-operand instruction in which the dst field should
- * be used instead of src2).
- */
+ * be used instead of src2).
+ */
regop.n <<= 19;
if (regop.special)
{
/*****************************************************************************
- * relax_cobr:
- * Replace cobr instruction in a code fragment with equivalent branch and
- * compare instructions, so it can reach beyond a 13-bit displacement.
- * Set up an address fix/relocation for the new branch instruction.
- *
- **************************************************************************** */
-
-/* This "conditional jump" table maps cobr instructions into equivalent
- * compare and branch opcodes.
- */
-static
+ relax_cobr:
+ Replace cobr instruction in a code fragment with equivalent branch and
+ compare instructions, so it can reach beyond a 13-bit displacement.
+ Set up an address fix/relocation for the new branch instruction.
+
+ *************************************************************************** */
+
+/* This "conditional jump" table maps cobr instructions into
+ equivalent compare and branch opcodes. */
+static const
struct
- {
- long compare;
- long branch;
- }
+{
+ long compare;
+ long branch;
+}
coj[] =
{ /* COBR OPCODE: */
- CHKBIT, BNO, /* 0x30 - bbc */
- CMPO, BG, /* 0x31 - cmpobg */
- CMPO, BE, /* 0x32 - cmpobe */
- CMPO, BGE, /* 0x33 - cmpobge */
- CMPO, BL, /* 0x34 - cmpobl */
- CMPO, BNE, /* 0x35 - cmpobne */
- CMPO, BLE, /* 0x36 - cmpoble */
- CHKBIT, BO, /* 0x37 - bbs */
- CMPI, BNO, /* 0x38 - cmpibno */
- CMPI, BG, /* 0x39 - cmpibg */
- CMPI, BE, /* 0x3a - cmpibe */
- CMPI, BGE, /* 0x3b - cmpibge */
- CMPI, BL, /* 0x3c - cmpibl */
- CMPI, BNE, /* 0x3d - cmpibne */
- CMPI, BLE, /* 0x3e - cmpible */
- CMPI, BO, /* 0x3f - cmpibo */
+ { CHKBIT, BNO }, /* 0x30 - bbc */
+ { CMPO, BG }, /* 0x31 - cmpobg */
+ { CMPO, BE }, /* 0x32 - cmpobe */
+ { CMPO, BGE }, /* 0x33 - cmpobge */
+ { CMPO, BL }, /* 0x34 - cmpobl */
+ { CMPO, BNE }, /* 0x35 - cmpobne */
+ { CMPO, BLE }, /* 0x36 - cmpoble */
+ { CHKBIT, BO }, /* 0x37 - bbs */
+ { CMPI, BNO }, /* 0x38 - cmpibno */
+ { CMPI, BG }, /* 0x39 - cmpibg */
+ { CMPI, BE }, /* 0x3a - cmpibe */
+ { CMPI, BGE }, /* 0x3b - cmpibge */
+ { CMPI, BL }, /* 0x3c - cmpibl */
+ { CMPI, BNE }, /* 0x3d - cmpibne */
+ { CMPI, BLE }, /* 0x3e - cmpible */
+ { CMPI, BO }, /* 0x3f - cmpibo */
};
static
/* Bit fields from cobr instruction */
long bp_bits; /* Branch prediction bits from cobr instruction */
long instr; /* A single i960 instruction */
- char *iP; /*->instruction to be replaced */
+ /* ->instruction to be replaced */
+ char *iP;
fixS *fixP; /* Relocation that can be done at assembly time */
/* PICK UP & PARSE COBR INSTRUCTION */
/*****************************************************************************
- * reloc_callj: Relocate a 'callj' instruction
- *
- * This is a "non-(GNU)-standard" machine-dependent hook. The base
- * assembler calls it when it decides it can relocate an address at
- * assembly time instead of emitting a relocation directive.
- *
- * Check to see if the relocation involves a 'callj' instruction to a:
- * sysproc: Replace the default 'call' instruction with a 'calls'
- * leafproc: Replace the default 'call' instruction with a 'bal'.
- * other proc: Do nothing.
- *
- * See b.out.h for details on the 'n_other' field in a symbol structure.
- *
- * IMPORTANT!:
- * Assumes the caller has already figured out, in the case of a leafproc,
- * to use the 'bal' entry point, and has substituted that symbol into the
- * passed fixup structure.
- *
- **************************************************************************** */
+ reloc_callj: Relocate a 'callj' instruction
+
+ This is a "non-(GNU)-standard" machine-dependent hook. The base
+ assembler calls it when it decides it can relocate an address at
+ assembly time instead of emitting a relocation directive.
+
+ Check to see if the relocation involves a 'callj' instruction to a:
+ sysproc: Replace the default 'call' instruction with a 'calls'
+ leafproc: Replace the default 'call' instruction with a 'bal'.
+ other proc: Do nothing.
+
+ See b.out.h for details on the 'n_other' field in a symbol structure.
+
+ IMPORTANT!:
+ Assumes the caller has already figured out, in the case of a leafproc,
+ to use the 'bal' entry point, and has substituted that symbol into the
+ passed fixup structure.
+
+ *************************************************************************** */
void
reloc_callj (fixP)
- fixS *fixP; /* Relocation that can be done at assembly time */
+ /* Relocation that can be done at assembly time */
+ fixS *fixP;
{
- char *where; /*->the binary for the instruction being relocated */
+ /* Points to the binary for the instruction being relocated. */
+ char *where;
- if (!fixP->fx_callj)
+ if (!fixP->fx_tcbit)
{
+ /* This wasn't a callj instruction in the first place */
return;
- } /* This wasn't a callj instruction in the first place */
+ }
where = fixP->fx_frag->fr_literal + fixP->fx_where;
if (TC_S_IS_SYSPROC (fixP->fx_addsy))
{
- /* Symbol is a .sysproc: replace 'call' with 'calls'.
- * System procedure number is (other-1).
- */
+ /* Symbol is a .sysproc: replace 'call' with 'calls'. System
+ procedure number is (other-1). */
md_number_to_chars (where, CALLS | TC_S_GET_SYSPROC (fixP->fx_addsy), 4);
- /* Nothing else needs to be done for this instruction.
- * Make sure 'md_number_to_field()' will perform a no-op.
- */
+ /* Nothing else needs to be done for this instruction. Make
+ sure 'md_number_to_field()' will perform a no-op. */
fixP->fx_bit_fixP = (bit_fixS *) 1;
}
else if (TC_S_IS_CALLNAME (fixP->fx_addsy))
{
/* Should not happen: see block comment above */
- as_fatal ("Trying to 'bal' to %s", S_GET_NAME (fixP->fx_addsy));
-
+ as_fatal (_("Trying to 'bal' to %s"), S_GET_NAME (fixP->fx_addsy));
}
else if (TC_S_IS_BALNAME (fixP->fx_addsy))
{
- /* Replace 'call' with 'bal'; both instructions have
- * the same format, so calling code should complete
- * relocation as if nothing happened here.
- */
+ /* Replace 'call' with 'bal'; both instructions have the same
+ format, so calling code should complete relocation as if
+ nothing happened here. */
md_number_to_chars (where, BAL, 4);
}
else if (TC_S_IS_BADPROC (fixP->fx_addsy))
{
- as_bad ("Looks like a proc, but can't tell what kind.\n");
+ as_bad (_("Looks like a proc, but can't tell what kind.\n"));
} /* switch on proc type */
/* else Symbol is neither a sysproc nor a leafproc */
-
- return;
-} /* reloc_callj() */
+}
/*****************************************************************************
- * s_leafproc: process .leafproc pseudo-op
- *
- * .leafproc takes two arguments, the second one is optional:
- * arg[1]: name of 'call' entry point to leaf procedure
- * arg[2]: name of 'bal' entry point to leaf procedure
- *
- * If the two arguments are identical, or if the second one is missing,
- * the first argument is taken to be the 'bal' entry point.
- *
- * If there are 2 distinct arguments, we must make sure that the 'bal'
- * entry point immediately follows the 'call' entry point in the linked
- * list of symbols.
- *
- **************************************************************************** */
+ s_leafproc: process .leafproc pseudo-op
+
+ .leafproc takes two arguments, the second one is optional:
+ arg[1]: name of 'call' entry point to leaf procedure
+ arg[2]: name of 'bal' entry point to leaf procedure
+
+ If the two arguments are identical, or if the second one is missing,
+ the first argument is taken to be the 'bal' entry point.
+
+ If there are 2 distinct arguments, we must make sure that the 'bal'
+ entry point immediately follows the 'call' entry point in the linked
+ list of symbols.
+
+ *************************************************************************** */
static void
s_leafproc (n_ops, args)
int n_ops; /* Number of operands */
if ((n_ops != 1) && (n_ops != 2))
{
- as_bad ("should have 1 or 2 operands");
+ as_bad (_("should have 1 or 2 operands"));
return;
} /* Check number of arguments */
if (TC_S_IS_CALLNAME (callP))
{
- as_warn ("Redefining leafproc %s", S_GET_NAME (callP));
+ as_warn (_("Redefining leafproc %s"), S_GET_NAME (callP));
} /* is leafproc */
/* If that was the only argument, use it as the 'bal' entry point.
- * Otherwise, mark it as the 'call' entry point and find or create
- * another symbol for the 'bal' entry point.
- */
+ * Otherwise, mark it as the 'call' entry point and find or create
+ * another symbol for the 'bal' entry point.
+ */
if ((n_ops == 1) || !strcmp (args[1], args[2]))
{
TC_S_FORCE_TO_BALNAME (callP);
balP = symbol_find_or_make (args[2]);
if (TC_S_IS_CALLNAME (balP))
{
- as_warn ("Redefining leafproc %s", S_GET_NAME (balP));
+ as_warn (_("Redefining leafproc %s"), S_GET_NAME (balP));
}
TC_S_FORCE_TO_BALNAME (balP);
tc_set_bal_of_call (callP, balP);
} /* if only one arg, or the args are the same */
-
- return;
-} /* s_leafproc() */
+}
/*
- * s_sysproc: process .sysproc pseudo-op
- *
- * .sysproc takes two arguments:
- * arg[1]: name of entry point to system procedure
- * arg[2]: 'entry_num' (index) of system procedure in the range
- * [0,31] inclusive.
- *
- * For [ab].out, we store the 'entrynum' in the 'n_other' field of
- * the symbol. Since that entry is normally 0, we bias 'entrynum'
- * by adding 1 to it. It must be unbiased before it is used.
- */
+ s_sysproc: process .sysproc pseudo-op
+
+ .sysproc takes two arguments:
+ arg[1]: name of entry point to system procedure
+ arg[2]: 'entry_num' (index) of system procedure in the range
+ [0,31] inclusive.
+
+ For [ab].out, we store the 'entrynum' in the 'n_other' field of
+ the symbol. Since that entry is normally 0, we bias 'entrynum'
+ by adding 1 to it. It must be unbiased before it is used. */
static void
s_sysproc (n_ops, args)
int n_ops; /* Number of operands */
if (n_ops != 2)
{
- as_bad ("should have two operands");
+ as_bad (_("should have two operands"));
return;
} /* bad arg count */
|| (offs (exp) < 0)
|| (offs (exp) > 31))
{
- as_bad ("'entry_num' must be absolute number in [0,31]");
+ as_bad (_("'entry_num' must be absolute number in [0,31]"));
return;
}
if (TC_S_IS_SYSPROC (symP))
{
- as_warn ("Redefining entrynum for sysproc %s", S_GET_NAME (symP));
+ as_warn (_("Redefining entrynum for sysproc %s"), S_GET_NAME (symP));
} /* redefining */
TC_S_SET_SYSPROC (symP, offs (exp)); /* encode entry number */
TC_S_FORCE_TO_SYSPROC (symP);
-
- return;
-} /* s_sysproc() */
+}
/*****************************************************************************
- * shift_ok:
- * Determine if a "shlo" instruction can be used to implement a "ldconst".
- * This means that some number X < 32 can be shifted left to produce the
- * constant of interest.
- *
- * Return the shift count, or 0 if we can't do it.
- * Caller calculates X by shifting original constant right 'shift' places.
- *
- **************************************************************************** */
+ shift_ok:
+ Determine if a "shlo" instruction can be used to implement a "ldconst".
+ This means that some number X < 32 can be shifted left to produce the
+ constant of interest.
+
+ Return the shift count, or 0 if we can't do it.
+ Caller calculates X by shifting original constant right 'shift' places.
+
+ *************************************************************************** */
static
int
shift_ok (n)
}
-/*****************************************************************************
- * syntax: issue syntax error
- *
- **************************************************************************** */
+/* syntax: issue syntax error */
+
static void
syntax ()
{
- as_bad ("syntax error");
+ as_bad (_("syntax error"));
} /* syntax() */
-/*****************************************************************************
- * targ_has_sfr:
- * Return TRUE iff the target architecture supports the specified
- * special-function register (sfr).
- *
- **************************************************************************** */
+/* targ_has_sfr:
+
+ Return TRUE iff the target architecture supports the specified
+ special-function register (sfr). */
+
static
int
targ_has_sfr (n)
case ARCH_KA:
case ARCH_KB:
case ARCH_MC:
+ case ARCH_JX:
return 0;
+ case ARCH_HX:
+ return ((0 <= n) && (n <= 4));
case ARCH_CA:
default:
return ((0 <= n) && (n <= 2));
}
-/*****************************************************************************
- * targ_has_iclass:
- * Return TRUE iff the target architecture supports the indicated
- * class of instructions.
- *
- **************************************************************************** */
+/* targ_has_iclass:
+
+ Return TRUE iff the target architecture supports the indicated
+ class of instructions. */
static
int
targ_has_iclass (ic)
- int ic; /* Instruction class; one of:
- * I_BASE, I_CX, I_DEC, I_KX, I_FP, I_MIL, I_CASIM
- */
+ /* Instruction class; one of:
+ I_BASE, I_CX, I_DEC, I_KX, I_FP, I_MIL, I_CASIM, I_CX2, I_HX, I_HX2
+ */
+ int ic;
{
iclasses_seen |= ic;
switch (architecture)
case ARCH_MC:
return ic & (I_BASE | I_KX | I_FP | I_DEC | I_MIL);
case ARCH_CA:
- return ic & (I_BASE | I_CX | I_CASIM);
+ return ic & (I_BASE | I_CX | I_CX2 | I_CASIM);
+ case ARCH_JX:
+ return ic & (I_BASE | I_CX2 | I_JX);
+ case ARCH_HX:
+ return ic & (I_BASE | I_CX2 | I_JX | I_HX);
default:
if ((iclasses_seen & (I_KX | I_FP | I_DEC | I_MIL))
- && (iclasses_seen & I_CX))
+ && (iclasses_seen & (I_CX | I_CX2)))
{
- as_warn ("architecture of opcode conflicts with that of earlier instruction(s)");
+ as_warn (_("architecture of opcode conflicts with that of earlier instruction(s)"));
iclasses_seen &= ~ic;
}
return 1;
}
}
+/* Handle the MRI .endian pseudo-op. */
-/* Parse an operand that is machine-specific.
- We just return without modifying the expression if we have nothing
- to do. */
-
-/* ARGSUSED */
-void
-md_operand (expressionP)
- expressionS *expressionP;
+static void
+s_endian (ignore)
+ int ignore;
{
+ char *name;
+ char c;
+
+ name = input_line_pointer;
+ c = get_symbol_end ();
+ if (strcasecmp (name, "little") == 0)
+ ;
+ else if (strcasecmp (name, "big") == 0)
+ as_bad (_("big endian mode is not supported"));
+ else
+ as_warn (_("ignoring unrecognized .endian type `%s'"), name);
+
+ *input_line_pointer = c;
+
+ demand_empty_rest_of_line ();
}
/* We have no need to default values of symbols. */
char *name;
{
return 0;
-} /* md_undefined_symbol() */
+}
/* Exactly what point is a PC-relative offset relative TO?
On the i960, they're relative to the address of the instruction,
return fixP->fx_where + fixP->fx_frag->fr_address;
}
+#ifdef BFD_ASSEMBLER
+int
+md_apply_fix (fixP, valp)
+ fixS *fixP;
+ valueT *valp;
+#else
void
md_apply_fix (fixP, val)
fixS *fixP;
long val;
+#endif
{
+#ifdef BFD_ASSEMBLER
+ long val = *valp;
+#endif
char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
if (!fixP->fx_bit_fixP)
{
+ /* For callx, we always want to write out zero, and emit a
+ symbolic relocation. */
+ if (fixP->fx_bsr)
+ val = 0;
+
+#ifdef OBJ_ELF
+ /* For ELF, we always emit relocations for external or weak
+ symbols. */
+ if (fixP->fx_addsy != NULL
+ && (S_IS_EXTERNAL (fixP->fx_addsy)
+ || S_IS_WEAK (fixP->fx_addsy)))
+ val = 0;
+#endif
- switch (fixP->fx_im_disp)
- {
- case 0:
- fixP->fx_addnumber = val;
- md_number_to_imm (place, val, fixP->fx_size, fixP);
- break;
- case 1:
- md_number_to_disp (place,
- (fixP->fx_pcrel
- ? val + fixP->fx_pcrel_adjust
- : val),
- fixP->fx_size);
- break;
- case 2: /* fix requested for .long .word etc */
- md_number_to_chars (place, val, fixP->fx_size);
- break;
- default:
- as_fatal ("Internal error in md_apply_fix() in file \"%s\"",
- __FILE__);
- }
+ fixP->fx_addnumber = val;
+
+#ifdef BFD_ASSEMBLER
+ /* HACK: With REL relocations this causes the offset in the code
+ to be doubled.
+
+ Guess: val is the old offset in the code, addnumber gets
+ passed back to md_gen_reloc() where it gets assigned to
+ addend, which the backend then writes back to the code (as
+ we're using REL, not RELA relocations). COFF must be working
+ without this hack, but I don't see how or why.
+
+ apeppere and martindo 22-10-1998. */
+ fixP->fx_addnumber = 0;
+#endif
+
+ md_number_to_imm (place, val, fixP->fx_size, fixP);
}
else
- {
- md_number_to_field (place, val, fixP->fx_bit_fixP);
- }
+ md_number_to_field (place, val, fixP->fx_bit_fixP);
- return;
-} /* md_apply_fix() */
+#ifdef BFD_ASSEMBLER
+ return 0;
+#endif
+}
#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
void
fixS *fixP;
relax_addressT segment_address_in_file;
{
- static unsigned char nbytes_r_length[] =
- {42, 0, 1, 42, 2};
+ static const unsigned char nbytes_r_length[] = {42, 0, 1, 42, 2};
struct relocation_info ri;
symbolS *symbolP;
- /* JF this is for paranoia */
memset ((char *) &ri, '\0', sizeof (ri));
symbolP = fixP->fx_addsy;
know (symbolP != 0 || fixP->fx_r_type != NO_RELOC);
ri.r_bsr = fixP->fx_bsr; /*SAC LD RELAX HACK */
/* These two 'cuz of NS32K */
- ri.r_callj = fixP->fx_callj;
+ ri.r_callj = fixP->fx_tcbit;
if (fixP->fx_bit_fixP)
- {
- ri.r_length = 2;
- }
+ ri.r_length = 2;
else
- {
- ri.r_length = nbytes_r_length[fixP->fx_size];
- }
+ ri.r_length = nbytes_r_length[fixP->fx_size];
ri.r_pcrel = fixP->fx_pcrel;
ri.r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file;
}
ri.r_extern = 0;
}
- else if (linkrelax || !S_IS_DEFINED (symbolP))
+ else if (linkrelax || !S_IS_DEFINED (symbolP) || fixP->fx_bsr)
{
ri.r_extern = 1;
ri.r_index = symbolP->sy_number;
/* Output the relocation information in machine-dependent form. */
md_ri_to_chars (where, &ri);
-
- return;
-} /* tc_bout_fix_to_chars() */
+}
#endif /* OBJ_AOUT or OBJ_BOUT */
-/* Align an address by rounding it up to the specified boundary.
- */
+#if defined (OBJ_COFF) && defined (BFD)
+short
+tc_coff_fix2rtype (fixP)
+ fixS *fixP;
+{
+ if (fixP->fx_bsr)
+ abort ();
+
+ if (fixP->fx_pcrel == 0 && fixP->fx_size == 4)
+ return R_RELLONG;
+
+ if (fixP->fx_pcrel != 0 && fixP->fx_size == 4)
+ return R_IPRMED;
+
+ abort ();
+ return 0;
+}
+
+int
+tc_coff_sizemachdep (frag)
+ fragS *frag;
+{
+ if (frag->fr_next)
+ return frag->fr_next->fr_address - frag->fr_address;
+ else
+ return 0;
+}
+#endif
+
+/* Align an address by rounding it up to the specified boundary. */
valueT
md_section_align (seg, addr)
segT seg;
valueT addr; /* Address to be rounded up */
{
- return ((addr + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg]));
-} /* md_section_align() */
+ int align;
+#ifdef BFD_ASSEMBLER
+ align = bfd_get_section_alignment (stdoutput, seg);
+#else
+ align = section_alignment[(int) seg];
+#endif
+ return (addr + (1 << align) - 1) & (-1 << align);
+}
+
+extern int coff_flags;
#ifdef OBJ_COFF
void
tc_headers_hook (headers)
object_headers *headers;
{
- /* FIXME: remove this line *//* unsigned short arch_flag = 0; */
-
- if (iclasses_seen == I_BASE)
- {
- headers->filehdr.f_flags |= F_I960CORE;
- }
- else if (iclasses_seen & I_CX)
- {
- headers->filehdr.f_flags |= F_I960CA;
- }
- else if (iclasses_seen & I_MIL)
- {
- headers->filehdr.f_flags |= F_I960MC;
- }
- else if (iclasses_seen & (I_DEC | I_FP))
+ switch (architecture)
{
- headers->filehdr.f_flags |= F_I960KB;
+ case ARCH_KA:
+ coff_flags |= F_I960KA;
+ break;
+
+ case ARCH_KB:
+ coff_flags |= F_I960KB;
+ break;
+
+ case ARCH_MC:
+ coff_flags |= F_I960MC;
+ break;
+
+ case ARCH_CA:
+ coff_flags |= F_I960CA;
+ break;
+
+ case ARCH_JX:
+ coff_flags |= F_I960JX;
+ break;
+
+ case ARCH_HX:
+ coff_flags |= F_I960HX;
+ break;
+
+ default:
+ if (iclasses_seen == I_BASE)
+ coff_flags |= F_I960CORE;
+ else if (iclasses_seen & I_CX)
+ coff_flags |= F_I960CA;
+ else if (iclasses_seen & I_HX)
+ coff_flags |= F_I960HX;
+ else if (iclasses_seen & I_JX)
+ coff_flags |= F_I960JX;
+ else if (iclasses_seen & I_CX2)
+ coff_flags |= F_I960CA;
+ else if (iclasses_seen & I_MIL)
+ coff_flags |= F_I960MC;
+ else if (iclasses_seen & (I_DEC | I_FP))
+ coff_flags |= F_I960KB;
+ else
+ coff_flags |= F_I960KA;
+ break;
}
- else
- {
- headers->filehdr.f_flags |= F_I960KA;
- } /* set arch flag */
- if (flagseen['R'])
+ if (flag_readonly_data_in_text)
{
headers->filehdr.f_magic = I960RWMAGIC;
headers->aouthdr.magic = OMAGIC;
headers->filehdr.f_magic = I960ROMAGIC;
headers->aouthdr.magic = NMAGIC;
} /* set magic numbers */
-
- return;
-} /* tc_headers_hook() */
+}
#endif /* OBJ_COFF */
-/*
- * Things going on here:
- *
- * For bout, We need to assure a couple of simplifying
- * assumptions about leafprocs for the linker: the leafproc
- * entry symbols will be defined in the same assembly in
- * which they're declared with the '.leafproc' directive;
- * and if a leafproc has both 'call' and 'bal' entry points
- * they are both global or both local.
- *
- * For coff, the call symbol has a second aux entry that
- * contains the bal entry point. The bal symbol becomes a
- * label.
- *
- * For coff representation, the call symbol has a second aux entry that
- * contains the bal entry point. The bal symbol becomes a label.
- *
- */
+#ifndef BFD_ASSEMBLER
+
+/* Things going on here:
+
+ For bout, We need to assure a couple of simplifying
+ assumptions about leafprocs for the linker: the leafproc
+ entry symbols will be defined in the same assembly in
+ which they're declared with the '.leafproc' directive;
+ and if a leafproc has both 'call' and 'bal' entry points
+ they are both global or both local.
+
+ For coff, the call symbol has a second aux entry that
+ contains the bal entry point. The bal symbol becomes a
+ label.
+
+ For coff representation, the call symbol has a second aux entry that
+ contains the bal entry point. The bal symbol becomes a label. */
void
tc_crawl_symbol_chain (headers)
if (!S_IS_DEFINED (symbolP))
{
- as_bad ("leafproc symbol '%s' undefined", S_GET_NAME (symbolP));
+ as_bad (_("leafproc symbol '%s' undefined"), S_GET_NAME (symbolP));
} /* undefined leaf */
if (TC_S_IS_CALLNAME (symbolP))
{
S_SET_EXTERNAL (symbolP);
S_SET_EXTERNAL (balP);
- as_warn ("Warning: making leafproc entries %s and %s both global\n",
+ as_warn (_("Warning: making leafproc entries %s and %s both global\n"),
S_GET_NAME (symbolP), S_GET_NAME (balP));
} /* externality mismatch */
} /* if callname */
} /* walk the symbol chain */
+}
- return;
-} /* tc_crawl_symbol_chain() */
+#endif /* ! BFD_ASSEMBLER */
-/*
- * For aout or bout, the bal immediately follows the call.
- *
- * For coff, we cheat and store a pointer to the bal symbol
- * in the second aux entry of the call.
- */
+/* For aout or bout, the bal immediately follows the call.
+
+ For coff, we cheat and store a pointer to the bal symbol in the
+ second aux entry of the call. */
#undef OBJ_ABOUT
#ifdef OBJ_AOUT
#ifdef OBJ_COFF
- callP->sy_symbol.ost_auxent[1].x_bal.x_balntry = (int) balP;
+ callP->sy_tc = balP;
S_SET_NUMBER_AUXILIARY (callP, 2);
#else /* ! OBJ_COFF */
#ifdef OBJ_ABOUT
/* If the 'bal' entry doesn't immediately follow the 'call'
- * symbol, unlink it from the symbol list and re-insert it.
- */
+ * symbol, unlink it from the symbol list and re-insert it.
+ */
if (symbol_next (callP) != balP)
{
symbol_remove (balP, &symbol_rootP, &symbol_lastP);
} /* if not in order */
#else /* ! OBJ_ABOUT */
- (as yet unwritten.);
+ as_fatal ("Only supported for a.out, b.out, or COFF");
#endif /* ! OBJ_ABOUT */
#endif /* ! OBJ_COFF */
+}
- return;
-} /* tc_set_bal_of_call() */
-
-char *
-_tc_get_bal_of_call (callP)
+symbolS *
+tc_get_bal_of_call (callP)
symbolS *callP;
{
symbolS *retval;
know (TC_S_IS_CALLNAME (callP));
#ifdef OBJ_COFF
- retval = (symbolS *) (callP->sy_symbol.ost_auxent[1].x_bal.x_balntry);
+ retval = callP->sy_tc;
#else
#ifdef OBJ_ABOUT
retval = symbol_next (callP);
#else
- (as yet unwritten.);
+ as_fatal ("Only supported for a.out, b.out, or COFF");
#endif /* ! OBJ_ABOUT */
#endif /* ! OBJ_COFF */
know (TC_S_IS_BALNAME (retval));
- return ((char *) retval);
+ return retval;
} /* _tc_get_bal_of_call() */
void
#ifdef OBJ_COFF
symbolS *balP = tc_get_bal_of_call (symbolP);
+#if 0
/* second aux entry contains the bal entry point */
- /* S_SET_NUMBER_AUXILIARY(symbolP, 2); */
+ S_SET_NUMBER_AUXILIARY (symbolP, 2);
+#endif
symbolP->sy_symbol.ost_auxent[1].x_bal.x_balntry = S_GET_VALUE (balP);
- S_SET_STORAGE_CLASS (symbolP, (!SF_GET_LOCAL (symbolP) ? C_LEAFEXT : C_LEAFSTAT));
+ if (S_GET_STORAGE_CLASS (symbolP) == C_EXT)
+ S_SET_STORAGE_CLASS (symbolP, C_LEAFEXT);
+ else
+ S_SET_STORAGE_CLASS (symbolP, C_LEAFSTAT);
S_SET_DATA_TYPE (symbolP, S_GET_DATA_TYPE (symbolP) | (DT_FCN << N_BTSHFT));
/* fix up the bal symbol */
S_SET_STORAGE_CLASS (balP, C_LABEL);
#endif /* OBJ_COFF */
} /* only on calls */
-
- return;
-} /* tc_coff_symbol_emit_hook() */
+}
void
i960_handle_align (fragp)
fragS *fragp;
{
- fixS *fixp;
- segT old_seg = now_seg, this_seg;
- int old_subseg = now_subseg;
- int pad_size;
- extern struct frag *text_last_frag, *data_last_frag;
-
if (!linkrelax)
return;
+#ifndef OBJ_BOUT
+
+ as_bad (_("option --link-relax is only supported in b.out format"));
+ linkrelax = 0;
+ return;
+
+#else
+
/* The text section "ends" with another alignment reloc, to which we
aren't adding padding. */
if (fragp->fr_next == text_last_frag
|| fragp->fr_next == data_last_frag)
+ return;
+
+ /* alignment directive */
+ fix_new (fragp, fragp->fr_fix, fragp->fr_offset, 0, 0, 0,
+ (int) fragp->fr_type);
+#endif /* OBJ_BOUT */
+}
+
+int
+i960_validate_fix (fixP, this_segment_type, add_symbolPP)
+ fixS *fixP;
+ segT this_segment_type;
+ symbolS **add_symbolPP;
+{
+#define add_symbolP (*add_symbolPP)
+ if (fixP->fx_tcbit && TC_S_IS_CALLNAME (add_symbolP))
{
- return;
+ /* Relocation should be done via the associated 'bal'
+ entry point symbol. */
+
+ if (!TC_S_IS_BALNAME (tc_get_bal_of_call (add_symbolP)))
+ {
+ as_bad (_("No 'bal' entry point for leafproc %s"),
+ S_GET_NAME (add_symbolP));
+ return 1;
+ }
+ fixP->fx_addsy = add_symbolP = tc_get_bal_of_call (add_symbolP);
+ }
+#if 0
+ /* Still have to work out other conditions for these tests. */
+ {
+ if (fixP->fx_tcbit)
+ {
+ as_bad (_("callj to difference of two symbols"));
+ return 1;
+ }
+ reloc_callj (fixP);
+ if ((int) fixP->fx_bit_fixP == 13)
+ {
+ /* This is a COBR instruction. They have only a 13-bit
+ displacement and are only to be used for local branches:
+ flag as error, don't generate relocation. */
+ as_bad (_("can't use COBR format with external label"));
+ fixP->fx_addsy = NULL; /* No relocations please. */
+ return 1;
+ }
+ }
+#endif
+#undef add_symbolP
+ return 0;
+}
+
+#ifdef BFD_ASSEMBLER
+
+/* From cgen.c: */
+
+static short
+tc_bfd_fix2rtype (fixP)
+ fixS *fixP;
+{
+#if 0
+ if (fixP->fx_bsr)
+ abort ();
+#endif
+
+ if (fixP->fx_pcrel == 0 && fixP->fx_size == 4)
+ return BFD_RELOC_32;
+
+ if (fixP->fx_pcrel != 0 && fixP->fx_size == 4)
+ return BFD_RELOC_24_PCREL;
+
+ abort ();
+ return 0;
+}
+
+/* Translate internal representation of relocation info to BFD target
+ format.
+
+ FIXME: To what extent can we get all relevant targets to use this? */
+
+arelent *
+tc_gen_reloc (section, fixP)
+ asection *section;
+ fixS *fixP;
+{
+ arelent * reloc;
+
+ reloc = (arelent *) xmalloc (sizeof (arelent));
+
+ /* HACK: Is this right? */
+ fixP->fx_r_type = tc_bfd_fix2rtype (fixP);
+
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
+ if (reloc->howto == (reloc_howto_type *) NULL)
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "internal error: can't export reloc type %d (`%s')",
+ fixP->fx_r_type,
+ bfd_get_reloc_code_name (fixP->fx_r_type));
+ return NULL;
}
- /* alignment directive */
- fixp = fix_new (fragp, fragp->fr_fix, fragp->fr_offset, 0, 0, 0,
- (int) fragp->fr_type);
+ assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
+
+ reloc->sym_ptr_ptr = &fixP->fx_addsy->bsym;
+ reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
+ reloc->addend = fixP->fx_addnumber;
+
+ return reloc;
}
+/* end from cgen.c */
+
+#endif /* BFD_ASSEMBLER */
+
/* end of tc-i960.c */