* Many files: Use xmalloc rather than bfd_alloc_by_size_t.
+Mon Mar 17 11:21:09 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * as.h (bfd_alloc_by_size_t): Don't declare.
+ * Many files: Use xmalloc rather than bfd_alloc_by_size_t.
+
Sun Mar 16 13:49:21 1997 Philippe De Muyter <phdm@info.ucl.ac.be>
* symbols.c (symbol_new): Don't call debug_verify_symchain.
/* as.h - global header file
- Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 1996
+ Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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. */
#ifndef GAS
#define GAS 1
#ifdef BFD_ASSEMBLER
#include <bfd.h>
#endif
+#include <libiberty.h>
/* Define the standard progress macros. */
#include <progress.h>
extern int errno;
#endif
-/* This is needed for VMS. */
-#if ! defined (HAVE_UNLINK) && defined (HAVE_REMOVE)
+/* This is needed for VMS with DEC C. */
+#if ! defined (__GNUC__) && ! defined (HAVE_UNLINK) && defined (HAVE_REMOVE)
#define unlink remove
#endif
#define bcopy(src,dest,size) memcpy(dest,src,size)
#endif
-#ifdef BFD_ASSEMBLER
-/* This one doesn't get declared, but we're using it anyways. This
- should be fixed -- either it's part of the external interface or
- it's not. */
-extern PTR bfd_alloc_by_size_t PARAMS ((bfd *abfd, size_t sz));
-#endif
-
/* Make Saber happier on obstack.h. */
#ifdef SABER
#undef __PTR_TO_INT
constant length frag. */
rs_fill = 1,
- /* Align: Fr_offset: power of 2. Variable chars: fill pattern. */
+ /* Align. The fr_offset field holds the power of 2 to which to
+ align. The fr_var field holds the number of characters in the
+ fill pattern. The fr_subtype field holds the maximum number of
+ bytes to skip when aligning, or 0 if there is no maximum. */
rs_align,
- /* Align code: fr_offset: power of 2. Fill pattern is machine
- specific, defaulting to all zeros. */
+ /* Align code. The fr_offset field holds the power of 2 to which
+ to align. This type is only generated by machine specific
+ code, which is normally responsible for handling the fill
+ pattern. The fr_subtype field holds the maximum number of
+ bytes to skip when aligning, or 0 if there is no maximum. */
rs_align_code,
/* Org: Fr_offset, fr_symbol: address. 1 variable char: fill
/* name of emitted object file */
COMMON char *out_file_name;
+/* name of file defining extensions to the basic instruction set */
+COMMON char *insttbl_file_name;
+
/* TRUE if we need a second pass. */
COMMON int need_pass_2;
#endif
#ifdef USE_STDARG
-#if __GNUC__ >= 2
+#if (__GNUC__ >= 2) && !defined(VMS)
/* for use with -Wformat */
#define PRINTF_LIKE(FCN) void FCN (const char *format, ...) \
__attribute__ ((format (printf, 1, 2)))
char *input_scrub_include_file PARAMS ((char *filename, char *position));
char *input_scrub_new_file PARAMS ((char *filename));
char *input_scrub_next_buffer PARAMS ((char **bufp));
-PTR xmalloc PARAMS ((unsigned long size));
-PTR xrealloc PARAMS ((PTR ptr, unsigned long n));
int do_scrub_chars PARAMS ((int (*get) (char **), char *to, int tolen));
int gen_to_words PARAMS ((LITTLENUM_TYPE * words, int precision,
long exponent_bits));
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
+#define OBJ_HEADER "obj-coff.h"
+
#include "as.h"
#include "obstack.h"
#include "subsegs.h"
\f
void
-obj_symbol_new_hook (symbolP)
+coff_obj_symbol_new_hook (symbolP)
symbolS *symbolP;
{
char underscore = 0; /* Symbol has leading _ */
{
long sz = (OBJ_COFF_MAX_AUXENTRIES + 1) * sizeof (combined_entry_type);
- char *s = (char *) bfd_alloc_by_size_t (stdoutput, sz);
+ char *s = (char *) xmalloc (sz);
memset (s, 0, sz);
coffsymbol (symbolP->bsym)->native = (combined_entry_type *) s;
}
int offset;
int num;
{
- struct line_no *new_line = (struct line_no *) bfd_alloc_by_size_t (stdoutput,
- sizeof (struct line_no));
+ struct line_no *new_line =
+ (struct line_no *) xmalloc (sizeof (struct line_no));
if (!current_lineno_sym)
{
abort ();
}
void
-obj_read_begin_hook ()
+coff_obj_read_begin_hook ()
{
/* These had better be the same. Usually 18 bytes. */
#ifndef BFD_HEADERS
/* We need i entries for line numbers, plus 1 for the first
entry which BFD will override, plus 1 for the last zero
entry (a marker for BFD). */
- l = (alent *) bfd_alloc_by_size_t (stdoutput, (i + 2) * sizeof (alent));
+ l = (alent *) xmalloc ((i + 2) * sizeof (alent));
coffsymbol (symp->bsym)->lineno = l;
l[i + 1].line_number = 0;
l[i + 1].u.sym = NULL;
* 'w' for data
* 'd' (apparently m88k for data)
* 'x' for text
+ * 'r' for read-only data
* But if the argument is not a quoted string, treat it as a
* subsegment number.
*/
case 'd':
case 'w': flags &=~ SEC_READONLY; break;
case 'x': flags |= SEC_CODE; break;
+ case 'r': flags |= SEC_READONLY; break;
case 'i': /* STYP_INFO */
case 'l': /* STYP_LIB */
}
void
-obj_symbol_new_hook (symbolP)
+coff_obj_symbol_new_hook (symbolP)
symbolS *symbolP;
{
char underscore = 0; /* Symbol has leading _ */
#endif /* TE_PE */
void
-obj_read_begin_hook ()
+coff_obj_read_begin_hook ()
{
/* These had better be the same. Usually 18 bytes. */
#ifndef BFD_HEADERS
* order :
* . .file symbol
* . debug entries for functions
- * . fake symbols for the sections, including.text .data and .bss
+ * . fake symbols for the sections, including .text .data and .bss
* . defined symbols
* . undefined symbols
* But this is not mandatory. The only important point is to put the
* 'w' for data
* 'd' (apparently m88k for data)
* 'x' for text
+ * 'r' for read-only data
* But if the argument is not a quoted string, treat it as a
* subsegment number.
*/
case 'd':
case 'w': flags |= STYP_DATA; break;
case 'x': flags |= STYP_TEXT; break;
+ case 'r': flags |= STYP_LIT; break;
default:
as_warn("unknown section attribute '%c'",
*input_line_pointer);
{"optim", s_ignore, 0}, /* For sun386i cc (?) */
{"ident", s_ignore, 0}, /* we don't yet handle this. */
#endif
+ {"version", s_ignore, 0},
{"ABORT", s_abort, 0},
#ifdef TC_M88K
/* The m88k uses sdef instead of def. */
#endif
{NULL} /* end sentinel */
}; /* obj_pseudo_table */
+\f
+#ifdef BFD_ASSEMBLER
+
+/* Support for a COFF emulation. */
+
+static void
+coff_pop_insert ()
+{
+ pop_insert (obj_pseudo_table);
+}
+
+static int
+coff_sec_sym_ok_for_reloc (sec)
+ asection *sec;
+{
+ return 0;
+}
+
+static void
+no_func ()
+{
+ abort ();
+}
+
+const struct format_ops coff_format_ops =
+{
+ bfd_target_coff_flavour,
+ 0,
+ 1,
+ coff_frob_symbol,
+ coff_frob_file,
+ no_func,
+ 0, 0,
+ 0, 0,
+ 0,
+#if 0
+ obj_generate_asm_lineno,
+#else
+ no_func,
+#endif
+#if 0
+ obj_stab,
+#else
+ no_func,
+#endif
+ coff_sec_sym_ok_for_reloc,
+ coff_pop_insert,
+#if 0
+ obj_set_ext,
+#else
+ no_func,
+#endif
+ coff_obj_read_begin_hook,
+ coff_obj_symbol_new_hook,
+};
+
+#endif
/* tc-alpha.c - Processor-specific code for the DEC Alpha AXP CPU.
- Copyright (C) 1989, 93, 94, 95, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1989, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
Contributed by Carnegie Mellon University, 1993.
Written by Alessandro Forin, based on earlier gas-1.38 target CPU files.
Modified by Ken Raeburn for gas-2.x and ECOFF support.
Modified by Richard Henderson for ELF support.
- Modified by Klaus Kaempf for EVAX (openVMS/Alpha) support.
+ Modified by Klaus K"ampf for EVAX (openVMS/Alpha) support.
This file is part of GAS, the GNU Assembler.
struct alpha_macro
{
const char *name;
- void (*emit) PARAMS((const expressionS *, int, void *));
- void *arg;
+ void (*emit) PARAMS ((const expressionS *, int, const PTR));
+ const PTR arg;
enum alpha_macro_arg argsets[16];
};
\f
/* Prototypes for all local functions */
-static int tokenize_arguments PARAMS((char *, expressionS*, int));
+static int tokenize_arguments PARAMS ((char *, expressionS *, int));
static const struct alpha_opcode *find_opcode_match
- PARAMS((const struct alpha_opcode*, const expressionS*, int*, int*));
+ PARAMS ((const struct alpha_opcode *, const expressionS *, int *, int *));
static const struct alpha_macro *find_macro_match
- PARAMS((const struct alpha_macro*, const expressionS*, int*));
-static unsigned insert_operand PARAMS((unsigned, const struct alpha_operand*,
- offsetT, char *, unsigned));
-static void assemble_insn PARAMS((const struct alpha_opcode*,
- const expressionS*, int,
- struct alpha_insn*));
-static void emit_insn PARAMS((struct alpha_insn *));
-static void assemble_tokens_to_insn PARAMS((const char *, const expressionS*,
- int, struct alpha_insn *));
-static void assemble_tokens PARAMS((const char *, const expressionS*,
- int, int));
-
-static int load_expression PARAMS((int, const expressionS*, int *,
- expressionS*));
-
-static void emit_ldgp PARAMS((const expressionS*, int, void*));
-static void emit_division PARAMS((const expressionS*, int, void*));
-static void emit_lda PARAMS((const expressionS*, int, void*));
-static void emit_ldah PARAMS((const expressionS*, int, void*));
-static void emit_ir_load PARAMS((const expressionS*, int, void*));
-static void emit_loadstore PARAMS((const expressionS*, int, void*));
-static void emit_jsrjmp PARAMS((const expressionS*, int, void*));
-static void emit_ldX PARAMS((const expressionS*, int, void*));
-static void emit_ldXu PARAMS((const expressionS*, int, void*));
-static void emit_uldX PARAMS((const expressionS*, int, void*));
-static void emit_uldXu PARAMS((const expressionS*, int, void*));
-static void emit_ldil PARAMS((const expressionS*, int, void*));
-static void emit_stX PARAMS((const expressionS*, int, void*));
-static void emit_ustX PARAMS((const expressionS*, int, void*));
-static void emit_sextX PARAMS((const expressionS*, int, void*));
-static void emit_retjcr PARAMS((const expressionS*, int, void*));
-
-static void s_alpha_text PARAMS((int));
-static void s_alpha_data PARAMS((int));
+ PARAMS ((const struct alpha_macro *, const expressionS *, int *));
+static unsigned insert_operand
+ PARAMS ((unsigned, const struct alpha_operand *, offsetT, char *, unsigned));
+static void assemble_insn
+ PARAMS ((const struct alpha_opcode *, const expressionS *, int,
+ struct alpha_insn *));
+static void emit_insn PARAMS ((struct alpha_insn *));
+static void assemble_tokens_to_insn
+ PARAMS ((const char *, const expressionS *, int, struct alpha_insn *));
+static void assemble_tokens
+ PARAMS ((const char *, const expressionS *, int, int));
+
+static int load_expression
+ PARAMS ((int, const expressionS *, int *, expressionS *));
+
+static void emit_ldgp PARAMS ((const expressionS *, int, const PTR));
+static void emit_division PARAMS ((const expressionS *, int, const PTR));
+static void emit_lda PARAMS ((const expressionS *, int, const PTR));
+static void emit_ldah PARAMS ((const expressionS *, int, const PTR));
+static void emit_ir_load PARAMS ((const expressionS *, int, const PTR));
+static void emit_loadstore PARAMS ((const expressionS *, int, const PTR));
+static void emit_jsrjmp PARAMS ((const expressionS *, int, const PTR));
+static void emit_ldX PARAMS ((const expressionS *, int, const PTR));
+static void emit_ldXu PARAMS ((const expressionS *, int, const PTR));
+static void emit_uldX PARAMS ((const expressionS *, int, const PTR));
+static void emit_uldXu PARAMS ((const expressionS *, int, const PTR));
+static void emit_ldil PARAMS ((const expressionS *, int, const PTR));
+static void emit_stX PARAMS ((const expressionS *, int, const PTR));
+static void emit_ustX PARAMS ((const expressionS *, int, const PTR));
+static void emit_sextX PARAMS ((const expressionS *, int, const PTR));
+static void emit_retjcr PARAMS ((const expressionS *, int, const PTR));
+
+static void s_alpha_text PARAMS ((int));
+static void s_alpha_data PARAMS ((int));
#ifndef OBJ_ELF
-static void s_alpha_comm PARAMS((int));
+static void s_alpha_comm PARAMS ((int));
#endif
#if defined (OBJ_ECOFF) || defined (OBJ_EVAX)
-static void s_alpha_rdata PARAMS((int));
+static void s_alpha_rdata PARAMS ((int));
#endif
#ifdef OBJ_ECOFF
-static void s_alpha_sdata PARAMS((int));
+static void s_alpha_sdata PARAMS ((int));
#endif
#ifdef OBJ_ELF
-static void s_alpha_section PARAMS((int));
+static void s_alpha_section PARAMS ((int));
#endif
-static void s_alpha_gprel32 PARAMS((int));
-static void s_alpha_float_cons PARAMS((int));
-static void s_alpha_proc PARAMS((int));
-static void s_alpha_set PARAMS((int));
-static void s_alpha_base PARAMS((int));
-static void s_alpha_align PARAMS((int));
-static void s_alpha_stringer PARAMS((int));
-static void s_alpha_space PARAMS((int));
-
-static void create_literal_section PARAMS((const char *, segT*, symbolS**));
+#ifdef OBJ_EVAX
+static void s_alpha_section PARAMS ((int));
+#endif
+static void s_alpha_gprel32 PARAMS ((int));
+static void s_alpha_float_cons PARAMS ((int));
+static void s_alpha_proc PARAMS ((int));
+static void s_alpha_set PARAMS ((int));
+static void s_alpha_base PARAMS ((int));
+static void s_alpha_align PARAMS ((int));
+static void s_alpha_stringer PARAMS ((int));
+static void s_alpha_space PARAMS ((int));
+
+static void create_literal_section PARAMS ((const char *, segT *, symbolS **));
#ifndef OBJ_ELF
-static void select_gp_value PARAMS((void));
+static void select_gp_value PARAMS ((void));
#endif
-static void alpha_align PARAMS((int, char *, symbolS *));
+static void alpha_align PARAMS ((int, char *, symbolS *));
\f
/* Generic assembler global variables which must be defined by all
#endif /* OBJ_EVAX */
/* The cpu for which we are generating code */
-static unsigned alpha_target = AXP_OPCODE_ALL;
+static unsigned alpha_target = AXP_OPCODE_BASE;
static const char *alpha_target_name = "<all>";
/* The hash table of instruction opcodes */
#endif
#ifdef OBJ_EVAX
static segT alpha_link_section;
+static segT alpha_ctors_section;
+static segT alpha_dtors_section;
#endif
static segT alpha_lit8_section;
#endif
#ifdef OBJ_EVAX
static symbolS *alpha_link_symbol;
+static symbolS *alpha_ctors_symbol;
+static symbolS *alpha_dtors_symbol;
#endif
static symbolS *alpha_lit8_symbol;
+/* Literal for .litX+0x8000 within .lita */
+#ifdef OBJ_ECOFF
+static offsetT alpha_lit4_literal;
+static offsetT alpha_lit8_literal;
+#endif
+
/* Is the assembler not allowed to use $at? */
static int alpha_noat_on = 0;
static int alpha_flag_hash_long_names = 0; /* -+ */
static int alpha_flag_show_after_trunc = 0; /* -H */
-static int alpha_flag_no_hash_mixed_case = 0; /* -h NUM */
-
-/* Flag that determines how we map names. This takes several values, and
- * is set with the -h switch. A value of zero implies names should be
- * upper case, and the presence of the -h switch inhibits the case hack.
- * No -h switch at all sets alpha_vms_name_mapping to 0, and allows case hacking.
- * A value of 2 (set with -h2) implies names should be
- * all lower case, with no case hack. A value of 3 (set with -h3) implies
- * that case should be preserved. */
-
-/* If the -+ switch is given, then the hash is appended to any name that is
- * longer than 31 characters, regardless of the setting of the -h switch.
- */
-static char alpha_vms_name_mapping = 0;
+/* If the -+ switch is given, then a hash is appended to any name that is
+ * longer than 64 characters, else longer symbol names are truncated.
+ */
static int alpha_basereg_clobbered;
#endif
{ MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_FPR, MACRO_EXP, MACRO_EOA } },
- { "ldb", emit_ldX, (void *)0,
+ { "ldb", emit_ldX, (PTR)0,
{ MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA } },
- { "ldbu", emit_ldXu, (void *)0,
+ { "ldbu", emit_ldXu, (PTR)0,
{ MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA } },
- { "ldw", emit_ldX, (void *)1,
+ { "ldw", emit_ldX, (PTR)1,
{ MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA } },
- { "ldwu", emit_ldXu, (void *)1,
+ { "ldwu", emit_ldXu, (PTR)1,
{ MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA } },
- { "uldw", emit_uldX, (void*)1,
+ { "uldw", emit_uldX, (PTR)1,
{ MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA } },
- { "uldwu", emit_uldXu, (void*)1,
+ { "uldwu", emit_uldXu, (PTR)1,
{ MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA } },
- { "uldl", emit_uldX, (void*)2,
+ { "uldl", emit_uldX, (PTR)2,
{ MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA } },
- { "uldlu", emit_uldXu, (void*)2,
+ { "uldlu", emit_uldXu, (PTR)2,
{ MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA } },
- { "uldq", emit_uldXu, (void*)3,
+ { "uldq", emit_uldXu, (PTR)3,
{ MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA } },
{ MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_FPR, MACRO_EXP, MACRO_EOA } },
- { "stb", emit_stX, (void*)0,
+ { "stb", emit_stX, (PTR)0,
{ MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA } },
- { "stw", emit_stX, (void*)1,
+ { "stw", emit_stX, (PTR)1,
{ MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA } },
- { "ustw", emit_ustX, (void*)1,
+ { "ustw", emit_ustX, (PTR)1,
{ MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA } },
- { "ustl", emit_ustX, (void*)2,
+ { "ustl", emit_ustX, (PTR)2,
{ MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA } },
- { "ustq", emit_ustX, (void*)3,
+ { "ustq", emit_ustX, (PTR)3,
{ MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
MACRO_IR, MACRO_EXP, MACRO_EOA } },
{ "absq" emit_absq, 2, { EXP, IR } },
#endif
- { "sextb", emit_sextX, (void *)0,
+ { "sextb", emit_sextX, (PTR)0,
{ MACRO_IR, MACRO_IR, MACRO_EOA,
MACRO_IR, MACRO_EOA,
/* MACRO_EXP, MACRO_IR, MACRO_EOA */ } },
- { "sextw", emit_sextX, (void *)1,
+ { "sextw", emit_sextX, (PTR)1,
{ MACRO_IR, MACRO_IR, MACRO_EOA,
MACRO_IR, MACRO_EOA,
/* MACRO_EXP, MACRO_IR, MACRO_EOA */ } },
sec = subseg_new(".reginfo", (subsegT)0);
/* The ABI says this section should be loaded so that the running
program can access it. */
- bfd_set_section_flags(stdoutput, sec,
+ bfd_set_section_flags(stdoutput, sec,
SEC_ALLOC|SEC_LOAD|SEC_READONLY|SEC_DATA);
bfd_set_section_alignement(stdoutput, sec, 3);
#endif
unsigned flags;
} *p, m[] =
{
- { "21064", AXP_OPCODE_EV4|AXP_OPCODE_ALL },
- { "21066", AXP_OPCODE_EV4|AXP_OPCODE_ALL },
- { "21164", AXP_OPCODE_EV5|AXP_OPCODE_ALL },
- { "21164a", AXP_OPCODE_EV56|AXP_OPCODE_ALL },
- { "ev4", AXP_OPCODE_EV4|AXP_OPCODE_ALL },
- { "ev45", AXP_OPCODE_EV4|AXP_OPCODE_ALL },
- { "ev5", AXP_OPCODE_EV5|AXP_OPCODE_ALL },
- { "ev56", AXP_OPCODE_EV56|AXP_OPCODE_ALL },
- { "all", AXP_OPCODE_ALL },
+ { "21064", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
+ { "21064a", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
+ { "21066", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
+ { "21068", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
+ { "21164", AXP_OPCODE_BASE|AXP_OPCODE_EV5 },
+ /* Do we have CIX extension here? */
+ { "21164a", AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX },
+ /* Still same PALcodes? */
+ { "21164pc", (AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX
+ |AXP_OPCODE_CIX|AXP_OPCODE_MAX) },
+ /* All new PALcodes? Extras? */
+ { "21264", (AXP_OPCODE_BASE|AXP_OPCODE_BWX
+ |AXP_OPCODE_CIX|AXP_OPCODE_MAX) },
+
+ { "ev4", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
+ { "ev45", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
+ { "lca45", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
+ { "ev5", AXP_OPCODE_BASE|AXP_OPCODE_EV5 },
+ { "ev56", AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX },
+ { "pca56", (AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX
+ |AXP_OPCODE_CIX|AXP_OPCODE_MAX) },
+ { "ev6", (AXP_OPCODE_BASE|AXP_OPCODE_BWX
+ |AXP_OPCODE_CIX|AXP_OPCODE_MAX) },
+
+ { "all", AXP_OPCODE_BASE },
{ 0 }
};
-
+
for (p = m; p->name; ++p)
if (strcmp(arg, p->name) == 0)
{
}
break;
-#if OBJ_EVAX
- case '+': /* For g++. Hash any name > 31 chars long. */
+#ifdef OBJ_EVAX
+ case '+': /* For g++. Hash any name > 63 chars long. */
alpha_flag_hash_long_names = 1;
break;
alpha_flag_show_after_trunc = 1;
break;
- case 'h': /* No hashing of mixed-case names */
- {
- alpha_vms_name_mapping = atoi (arg);
- alpha_flag_no_hash_mixed_case = 1;
- }
+ case 'h': /* for gnu-c/vax compatibility. */
break;
#endif
#ifdef OBJ_EVAX
fputs ("\
VMS options:\n\
--+ hash encode names longer than 31 characters\n\
--H show new symbol after hash truncation\n\
--h NUM don't hash mixed-case names, and adjust case:\n\
- 0 = upper, 2 = lower, 3 = preserve case\n",
+-+ hash encode (don't truncate) names longer than 64 characters\n\
+-H show new symbol after hash truncation\n",
stream);
#endif
}
fixS *next = fixP->fx_next;
assert (next->fx_r_type == BFD_RELOC_ALPHA_GPDISP_LO16);
- fixP->fx_offset = (next->fx_frag->fr_address + next->fx_where
+ fixP->fx_offset = (next->fx_frag->fr_address + next->fx_where
- fixP->fx_frag->fr_address - fixP->fx_where);
value = (value - sign_extend_16 (value)) >> 16;
return 1;
#endif
#ifdef OBJ_ELF
- case BFD_RELOC_ALPHA_LITERAL:
+ case BFD_RELOC_ALPHA_ELF_LITERAL:
case BFD_RELOC_ALPHA_LITUSE:
return 1;
#endif
#ifdef OBJ_EVAX
case BFD_RELOC_ALPHA_LINKAGE:
+ case BFD_RELOC_ALPHA_CODEADDR:
return 1;
#endif
{
const struct alpha_operand *operand;
- if (fixP->fx_r_type <= BFD_RELOC_UNUSED)
+ if ((int)fixP->fx_r_type >= 0)
as_fatal ("unhandled relocation type %s",
bfd_get_reloc_code_name (fixP->fx_r_type));
- assert (fixP->fx_r_type < BFD_RELOC_UNUSED + alpha_num_operands);
- operand = &alpha_operands[fixP->fx_r_type - BFD_RELOC_UNUSED];
+ assert (-(int)fixP->fx_r_type < alpha_num_operands);
+ operand = &alpha_operands[-(int)fixP->fx_r_type];
/* The rest of these fixups only exist internally during symbol
- resolution and have no representation in the object file.
+ resolution and have no representation in the object file.
Therefore they must be completely resolved as constants. */
if (fixP->fx_addsy != 0
else
{
as_warn_where(fixP->fx_file, fixP->fx_line,
- "type %d reloc done?\n", fixP->fx_r_type);
+ "type %d reloc done?\n", (int)fixP->fx_r_type);
goto done;
}
-
+
write_done:
md_number_to_chars(fixpos, image, 4);
return 0;
}
-/*
+/*
* Look for a register name in the given symbol.
*/
num = name[0] - '0';
else if (name[0] != '0' && isdigit(name[1]) && name[2] == '\0')
{
- num = (name[0] - '0')*10 + name[1] - '0';
+ num = (name[0] - '0') * 10 + name[1] - '0';
if (num >= 32)
break;
}
case BFD_RELOC_ALPHA_GPDISP_HI16:
case BFD_RELOC_ALPHA_GPDISP_LO16:
case BFD_RELOC_ALPHA_GPDISP:
+#ifdef OBJ_ECOFF
case BFD_RELOC_ALPHA_LITERAL:
+#endif
+#ifdef OBJ_ELF
+ case BFD_RELOC_ALPHA_ELF_LITERAL:
+#endif
case BFD_RELOC_ALPHA_LITUSE:
case BFD_RELOC_GPREL32:
#ifdef OBJ_EVAX
case BFD_RELOC_ALPHA_LINKAGE:
+ case BFD_RELOC_ALPHA_CODEADDR:
#endif
return 1;
return 0;
default:
- assert(f->fx_r_type > BFD_RELOC_UNUSED &&
- f->fx_r_type < BFD_RELOC_UNUSED + alpha_num_operands);
+ assert((int)f->fx_r_type < 0 && -(int)f->fx_r_type < alpha_num_operands);
return 0;
}
}
but we can adjust the values contained within it? */
switch (f->fx_r_type)
{
+ case BFD_RELOC_ALPHA_GPDISP_HI16:
+ case BFD_RELOC_ALPHA_GPDISP_LO16:
+ case BFD_RELOC_ALPHA_GPDISP:
+ return 0;
+
+#ifdef OBJ_ECOFF
+ case BFD_RELOC_ALPHA_LITERAL:
+#endif
+#ifdef OBJ_ELF
+ case BFD_RELOC_ALPHA_ELF_LITERAL:
+#endif
+#ifdef OBJ_EVAX
+ case BFD_RELOC_ALPHA_LINKAGE:
+ case BFD_RELOC_ALPHA_CODEADDR:
+#endif
+ return 1;
+
+ case BFD_RELOC_ALPHA_LITUSE:
+ return 0;
+
case BFD_RELOC_GPREL32:
+ case BFD_RELOC_23_PCREL_S2:
+ case BFD_RELOC_32:
+ case BFD_RELOC_64:
+ case BFD_RELOC_ALPHA_HINT:
return 1;
+
default:
- return !alpha_force_relocation (f);
+ assert ((int)f->fx_r_type < 0
+ && - (int)f->fx_r_type < alpha_num_operands);
+ return 1;
}
/*NOTREACHED*/
}
{
arelent *reloc;
- reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
+ reloc = (arelent *) xmalloc (sizeof (arelent));
reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
/* Make sure none of our internal relocations make it this far.
They'd better have been fully resolved by this point. */
- assert (fixp->fx_r_type < BFD_RELOC_UNUSED);
+ assert ((int)fixp->fx_r_type > 0);
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
if (reloc->howto == NULL)
{
reloc->addend = fixp->fx_offset;
#ifdef OBJ_ELF
- /*
+ /*
* Ohhh, this is ugly. The problem is that if this is a local global
* symbol, the relocation will entirely be performed at link time, not
* at assembly time. bfd_perform_reloc doesn't know about this sort
char *old_input_line_pointer;
int saw_comma = 0, saw_arg = 0;
- memset (tok, 0, sizeof(*tok)*ntok);
+ memset (tok, 0, sizeof (*tok) * ntok);
- /* Save and restore input_line_pointer around this function */
+ /* Save and restore input_line_pointer around this function */
old_input_line_pointer = input_line_pointer;
input_line_pointer = str;
-
+
while (tok < end_tok && *input_line_pointer)
{
SKIP_WHITESPACE ();
match_failed:;
}
- while (++opcode-alpha_opcodes < alpha_num_opcodes
+ while (++opcode-alpha_opcodes < alpha_num_opcodes
&& !strcmp(opcode->name, first_opcode->name));
if (*pcpumatch)
}
++tokidx;
break;
-
+
match_failed:
while (*arg != MACRO_EOA)
++arg;
++arg;
}
}
- while (++macro-alpha_macros < alpha_num_macros
+ while (++macro-alpha_macros < alpha_num_macros
&& !strcmp(macro->name, first_macro->name));
return NULL;
if (val < min || val > max)
{
- const char *err =
+ const char *err =
"operand out of range (%s not between %d and %d)";
- char buf[sizeof(val)*3+2];
+ char buf[sizeof (val) * 3 + 2];
sprint_value(buf, val);
if (file)
{
const char *errmsg = NULL;
- insn = (*operand->insert)(insn, val, &errmsg);
+ insn = (*operand->insert) (insn, val, &errmsg);
if (errmsg)
- as_warn(errmsg);
+ as_warn (errmsg);
}
else
insn |= ((val & ((1 << operand->bits) - 1)) << operand->shift);
return insn;
}
-/*
+/*
* Turn an opcode description and a set of arguments into
* an instruction and a fixup.
*/
unsigned image;
int tokidx = 0;
- memset(insn, 0, sizeof(*insn));
+ memset (insn, 0, sizeof (*insn));
image = opcode->opcode;
for (argidx = opcode->operands; *argidx; ++argidx)
insn->insn = image;
}
-/*
+/*
* Actually output an instruction with its fixup.
*/
fixS *fixP;
/* Some fixups are only used internally and so have no howto */
- if (fixup->reloc > BFD_RELOC_UNUSED)
+ if ((int)fixup->reloc < 0)
size = 4, pcrel = 0;
#ifdef OBJ_ELF
/* These relocation types are only used internally. */
#endif
else
{
- reloc_howto_type *reloc_howto
+ reloc_howto_type *reloc_howto
= bfd_reloc_type_lookup (stdoutput, fixup->reloc);
assert (reloc_howto);
switch (fixup->reloc)
{
case BFD_RELOC_ALPHA_GPDISP_LO16:
+#ifdef OBJ_ECOFF
case BFD_RELOC_ALPHA_LITERAL:
+#endif
+#ifdef OBJ_ELF
+ case BFD_RELOC_ALPHA_ELF_LITERAL:
+#endif
case BFD_RELOC_GPREL32:
fixP->fx_no_overflow = 1;
break;
return;
}
}
-
+
if (found_something)
if (cpumatch)
as_bad ("inappropriate arguments for opcode `%s'", opname);
static const char * const extXh_op[] = { NULL, "extwh", "extlh", "extqh" };
static const char * const mskXl_op[] = { "mskbl", "mskwl", "mskll", "mskql" };
static const char * const mskXh_op[] = { NULL, "mskwh", "msklh", "mskqh" };
+static const char * const stX_op[] = { "stb", "stw", "stl", "stq" };
+static const char * const ldX_op[] = { "ldb", "ldw", "ldll", "ldq" };
+static const char * const ldXu_op[] = { "ldbu", "ldwu", NULL, NULL };
/* Implement the ldgp macro. */
-static void
+static void
emit_ldgp (tok, ntok, unused)
const expressionS *tok;
int ntok;
- void *unused;
+ const PTR unused;
{
#ifdef OBJ_AOUT
FIXME
emit_insn (&insn);
set_tok_preg (newtok[2], tok[0].X_add_number);
-
+
assemble_tokens_to_insn ("lda", newtok, 3, &insn);
#ifdef OBJ_ECOFF
as_bad ("macro requires $at register while noat in effect");
if (targreg == AXP_REG_AT)
as_bad ("macro requires $at while $at in use");
-
+
set_tok_reg (newtok[0], AXP_REG_AT);
}
else
as_bad ("macro requires $at register while noat in effect");
if (targreg == AXP_REG_AT)
as_bad ("macro requires $at while $at in use");
-
+
set_tok_reg (newtok[0], AXP_REG_AT);
}
else
assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
assert (insn.nfixups == 1);
- insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL;
+ insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL;
#endif /* OBJ_ELF */
#ifdef OBJ_EVAX
offsetT link;
#endif /* OBJ_EVAX */
emit_insn(&insn);
+
#ifndef OBJ_EVAX
emit_lituse = 1;
assemble_tokens ("addq", newtok, 3, 0);
}
#endif
+
basereg = targreg;
}
break;
/* for 64-bit addends, just put it in the literal pool */
#ifdef OBJ_EVAX
-
/* emit "ldq targreg, lit(basereg)" */
lit = add_to_link_pool (alpha_evax_proc.symbol,
section_symbol (absolute_section), addend);
set_tok_const (newtok[1], lit);
set_tok_preg (newtok[2], alpha_gp_register);
assemble_tokens ("ldq", newtok, 3, 0);
-
#else
if (alpha_lit8_section == NULL)
create_literal_section (".lit8",
&alpha_lit8_section,
&alpha_lit8_symbol);
- S_SET_VALUE (alpha_lit8_symbol, 0x8000);
+
+#ifdef OBJ_ECOFF
+ alpha_lit8_literal = add_to_literal_pool (alpha_lit8_symbol, 0x8000,
+ alpha_lita_section, 8);
+ if (alpha_lit8_literal >= 0x8000)
+ as_fatal ("overflow in literal (.lita) table");
+#endif
}
lit = add_to_literal_pool (NULL, addend, alpha_lit8_section, 8) - 0x8000;
if (lit >= 0x8000)
as_fatal ("overflow in literal (.lit8) table");
- /* emit "ldq litreg, .lit8+lit" */
+ /* emit "lda litreg, .lit8+0x8000" */
if (targreg == basereg)
{
}
else
set_tok_reg (newtok[0], targreg);
- set_tok_sym (newtok[1], alpha_lit8_symbol, lit);
+#ifdef OBJ_ECOFF
+ set_tok_sym (newtok[1], alpha_lita_symbol, alpha_lit8_literal);
+#endif
+#ifdef OBJ_ELF
+ set_tok_sym (newtok[1], alpha_lit8_symbol, 0x8000);
+#endif
+ set_tok_preg (newtok[2], alpha_gp_register);
+
+ assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
+
+ assert (insn.nfixups == 1);
+#ifdef OBJ_ECOFF
+ insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL;
+#endif
+#ifdef OBJ_ELF
+ insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL;
+#endif
+
+ emit_insn (&insn);
+
+ /* emit "ldq litreg, lit(litreg)" */
+
+ set_tok_const (newtok[1], lit);
+ set_tok_preg (newtok[2], newtok[0].X_add_number);
+
+ assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
+
+ assert (insn.nfixups < MAX_INSN_FIXUPS);
+ if (insn.nfixups > 0)
+ {
+ memmove (&insn.fixups[1], &insn.fixups[0],
+ sizeof(struct alpha_fixup) * insn.nfixups);
+ }
+ insn.nfixups++;
+ insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE;
+ insn.fixups[0].exp.X_op = O_constant;
+ insn.fixups[0].exp.X_add_number = 1;
+ emit_lituse = 0;
- assemble_tokens ("ldq", newtok, 2, 1); /* note this does recurse */
+ emit_insn (&insn);
/* emit "addq litreg, base, target" */
emit_lda (tok, ntok, unused)
const expressionS *tok;
int ntok;
- void *unused;
+ const PTR unused;
{
int basereg;
emit_ldah (tok, ntok, unused)
const expressionS *tok;
int ntok;
- void *unused;
+ const PTR unused;
{
expressionS newtok[3];
emit_ir_load (tok, ntok, opname)
const expressionS *tok;
int ntok;
- void *opname;
+ const PTR opname;
{
int basereg, lituse;
expressionS newtok[3];
}
emit_insn (&insn);
-#if OBJ_EVAX
- /* special hack. If the basereg is clobbered for a call
+#ifdef OBJ_EVAX
+ /* special hack. If the basereg is clobbered for a call
all lda's before the call don't have a basereg. */
if ((tok[0].X_op == O_register)
&& (tok[0].X_add_number == alpha_gp_register))
emit_loadstore (tok, ntok, opname)
const expressionS *tok;
int ntok;
- void *opname;
+ const PTR opname;
{
int basereg, lituse;
expressionS newtok[3];
struct alpha_insn insn;
-
+
if (ntok == 2)
basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register);
else
/* Load a half-word or byte as an unsigned value. */
-static void
+static void
emit_ldXu (tok, ntok, vlgsize)
const expressionS *tok;
int ntok;
- void *vlgsize;
+ const PTR vlgsize;
{
- expressionS newtok[3];
+ if (alpha_target & AXP_OPCODE_BWX)
+ emit_ir_load (tok, ntok, ldXu_op[(long)vlgsize]);
+ else
+ {
+ expressionS newtok[3];
- if (alpha_noat_on)
- as_bad ("macro requires $at register while noat in effect");
-
- /* emit "lda $at, exp" */
+ if (alpha_noat_on)
+ as_bad ("macro requires $at register while noat in effect");
- memcpy (newtok, tok, sizeof(expressionS)*ntok);
- newtok[0].X_add_number = AXP_REG_AT;
- assemble_tokens ("lda", newtok, ntok, 1);
+ /* emit "lda $at, exp" */
- /* emit "ldq_u targ, 0($at)" */
+ memcpy (newtok, tok, sizeof (expressionS) * ntok);
+ newtok[0].X_add_number = AXP_REG_AT;
+ assemble_tokens ("lda", newtok, ntok, 1);
- newtok[0] = tok[0];
- set_tok_const (newtok[1], 0);
- set_tok_preg (newtok[2], AXP_REG_AT);
- assemble_tokens ("ldq_u", newtok, 3, 1);
+ /* emit "ldq_u targ, 0($at)" */
- /* emit "extXl targ, $at, targ" */
+ newtok[0] = tok[0];
+ set_tok_const (newtok[1], 0);
+ set_tok_preg (newtok[2], AXP_REG_AT);
+ assemble_tokens ("ldq_u", newtok, 3, 1);
- set_tok_reg (newtok[1], AXP_REG_AT);
- newtok[2] = newtok[0];
- assemble_tokens (extXl_op[(long)vlgsize], newtok, 3, 1);
+ /* emit "extXl targ, $at, targ" */
+
+ set_tok_reg (newtok[1], AXP_REG_AT);
+ newtok[2] = newtok[0];
+ assemble_tokens (extXl_op[(long)vlgsize], newtok, 3, 1);
+ }
}
/* Load a half-word or byte as a signed value. */
-static void
+static void
emit_ldX (tok, ntok, vlgsize)
const expressionS *tok;
int ntok;
- void *vlgsize;
+ const PTR vlgsize;
{
emit_ldXu (tok, ntok, vlgsize);
assemble_tokens (sextX_op[(long)vlgsize], tok, 1, 1);
emit_uldXu (tok, ntok, vlgsize)
const expressionS *tok;
int ntok;
- void *vlgsize;
+ const PTR vlgsize;
{
long lgsize = (long)vlgsize;
expressionS newtok[3];
/* emit "lda $at, exp" */
- memcpy (newtok, tok, sizeof(expressionS)*ntok);
+ memcpy (newtok, tok, sizeof (expressionS) * ntok);
newtok[0].X_add_number = AXP_REG_AT;
assemble_tokens ("lda", newtok, ntok, 1);
newtok[2] = tok[0];
assemble_tokens ("or", newtok, 3, 1);
}
-
+
/* Load an integral value from an unaligned address as a signed value.
Note that quads should get funneled to the unsigned load since we
don't have to do the sign extension. */
emit_uldX (tok, ntok, vlgsize)
const expressionS *tok;
int ntok;
- void *vlgsize;
+ const PTR vlgsize;
{
emit_uldXu (tok, ntok, vlgsize);
assemble_tokens (sextX_op[(long)vlgsize], tok, 1, 1);
emit_ldil (tok, ntok, unused)
const expressionS *tok;
int ntok;
- void *unused;
+ const PTR unused;
{
expressionS newtok[2];
static void
emit_stX (tok, ntok, vlgsize)
const expressionS *tok;
- void *vlgsize;
+ int ntok;
+ const PTR vlgsize;
{
int lgsize = (int)(long)vlgsize;
- expressionS newtok[3];
- if (alpha_noat_on)
- as_bad("macro requires $at register while noat in effect");
+ if (alpha_target & AXP_OPCODE_BWX)
+ emit_loadstore (tok, ntok, stX_op[lgsize]);
+ else
+ {
+ expressionS newtok[3];
- /* emit "lda $at, exp" */
+ if (alpha_noat_on)
+ as_bad("macro requires $at register while noat in effect");
- memcpy (newtok, tok, sizeof(expressionS)*ntok);
- newtok[0].X_add_number = AXP_REG_AT;
- assemble_tokens ("lda", newtok, ntok, 1);
+ /* emit "lda $at, exp" */
- /* emit "ldq_u $t9, 0($at)" */
+ memcpy (newtok, tok, sizeof (expressionS) * ntok);
+ newtok[0].X_add_number = AXP_REG_AT;
+ assemble_tokens ("lda", newtok, ntok, 1);
- set_tok_reg (newtok[0], AXP_REG_T9);
- set_tok_const (newtok[1], 0);
- set_tok_preg (newtok[2], AXP_REG_AT);
- assemble_tokens ("ldq_u", newtok, 3, 1);
+ /* emit "ldq_u $t9, 0($at)" */
- /* emit "insXl src, $at, $t10" */
+ set_tok_reg (newtok[0], AXP_REG_T9);
+ set_tok_const (newtok[1], 0);
+ set_tok_preg (newtok[2], AXP_REG_AT);
+ assemble_tokens ("ldq_u", newtok, 3, 1);
- newtok[0] = tok[0];
- set_tok_reg (newtok[1], AXP_REG_AT);
- set_tok_reg (newtok[2], AXP_REG_T10);
- assemble_tokens (insXl_op[lgsize], newtok, 3, 1);
+ /* emit "insXl src, $at, $t10" */
- /* emit "mskXl $t9, $at, $t9" */
+ newtok[0] = tok[0];
+ set_tok_reg (newtok[1], AXP_REG_AT);
+ set_tok_reg (newtok[2], AXP_REG_T10);
+ assemble_tokens (insXl_op[lgsize], newtok, 3, 1);
- set_tok_reg (newtok[0], AXP_REG_T9);
- newtok[2] = newtok[0];
- assemble_tokens (mskXl_op[lgsize], newtok, 3, 1);
+ /* emit "mskXl $t9, $at, $t9" */
- /* emit "or $t9, $t10, $t9" */
+ set_tok_reg (newtok[0], AXP_REG_T9);
+ newtok[2] = newtok[0];
+ assemble_tokens (mskXl_op[lgsize], newtok, 3, 1);
- set_tok_reg (newtok[1], AXP_REG_T10);
- assemble_tokens ("or", newtok, 3, 1);
+ /* emit "or $t9, $t10, $t9" */
- /* emit "stq_u $t9, 0($at) */
+ set_tok_reg (newtok[1], AXP_REG_T10);
+ assemble_tokens ("or", newtok, 3, 1);
- set_tok_const (newtok[1], 0);
- set_tok_preg (newtok[2], AXP_REG_AT);
- assemble_tokens ("stq_u", newtok, 3, 1);
+ /* emit "stq_u $t9, 0($at) */
+
+ set_tok_const (newtok[1], 0);
+ set_tok_preg (newtok[2], AXP_REG_AT);
+ assemble_tokens ("stq_u", newtok, 3, 1);
+ }
}
/* Store an integer to an unaligned address. */
emit_ustX (tok, ntok, vlgsize)
const expressionS *tok;
int ntok;
- void *vlgsize;
+ const PTR vlgsize;
{
int lgsize = (int)(long)vlgsize;
expressionS newtok[3];
/* emit "lda $at, exp" */
- memcpy (newtok, tok, sizeof(expressionS)*ntok);
+ memcpy (newtok, tok, sizeof (expressionS) * ntok);
newtok[0].X_add_number = AXP_REG_AT;
assemble_tokens ("lda", newtok, ntok, 1);
emit_sextX (tok, ntok, vlgsize)
const expressionS *tok;
int ntok;
- void *vlgsize;
+ const PTR vlgsize;
{
- int bitshift = 64 - 8*(1 << (long)vlgsize);
- expressionS newtok[3];
+ long lgsize = (long)vlgsize;
- /* emit "sll src,bits,dst" */
+ if (alpha_target & AXP_OPCODE_BWX)
+ assemble_tokens (sextX_op[lgsize], tok, ntok, 0);
+ else
+ {
+ int bitshift = 64 - 8 * (1 << lgsize);
+ expressionS newtok[3];
- newtok[0] = tok[0];
- set_tok_const (newtok[1], bitshift);
- newtok[2] = tok[ntok - 1];
- assemble_tokens ("sll", newtok, 3, 1);
+ /* emit "sll src,bits,dst" */
+
+ newtok[0] = tok[0];
+ set_tok_const (newtok[1], bitshift);
+ newtok[2] = tok[ntok - 1];
+ assemble_tokens ("sll", newtok, 3, 1);
- /* emit "sra dst,bits,dst" */
+ /* emit "sra dst,bits,dst" */
- newtok[0] = newtok[2];
- assemble_tokens ("sra", newtok, 3, 1);
+ newtok[0] = newtok[2];
+ assemble_tokens ("sra", newtok, 3, 1);
+ }
}
/* Implement the division and modulus macros. */
/* Make register usage like in normal procedure call.
Don't clobber PV and RA. */
-static void
+static void
emit_division (tok, ntok, symname)
const expressionS *tok;
int ntok;
- void *symname;
+ const PTR symname;
{
/* DIVISION and MODULUS. Yech.
*
* mov R0,result
*
* with appropriate optimizations if R0,R16,R17 are the registers
- * specified by the compiler.
+ * specified by the compiler.
*/
int xr, yr, rr;
xr = regno (tok[0].X_add_number);
yr = regno (tok[1].X_add_number);
-
+
if (ntok < 3)
rr = xr;
else
#else /* !OBJ_EVAX */
-static void
+static void
emit_division (tok, ntok, symname)
const expressionS *tok;
int ntok;
- void *symname;
+ const PTR symname;
{
/* DIVISION and MODULUS. Yech.
* Convert
* mov t12,result
*
* with appropriate optimizations if t10,t11,t12 are the registers
- * specified by the compiler.
+ * specified by the compiler.
*/
int xr, yr, rr;
xr = regno (tok[0].X_add_number);
yr = regno (tok[1].X_add_number);
-
+
if (ntok < 3)
rr = xr;
else
emit_jsrjmp (tok, ntok, vopname)
const expressionS *tok;
int ntok;
- void *vopname;
+ const PTR vopname;
{
const char *opname = (const char *) vopname;
struct alpha_insn insn;
emit_insn (&insn);
-#if OBJ_EVAX
+#ifdef OBJ_EVAX
alpha_basereg_clobbered = 0;
/* reload PV from 0(FP) if it is our current base register. */
emit_retjcr (tok, ntok, vopname)
const expressionS *tok;
int ntok;
- void *vopname;
+ const PTR vopname;
{
const char *opname = (const char *)vopname;
expressionS newtok[3];
alpha_insn_label = NULL;
alpha_auto_align_on = 1;
alpha_current_align = 0;
-}
+}
/* Handle the .data pseudo-op. This is like the usual one, but it
clears alpha_insn_label and restores auto alignment. */
alpha_insn_label = NULL;
alpha_auto_align_on = 1;
alpha_current_align = 0;
-}
+}
-#ifndef OBJ_ELF
+#ifdef OBJ_ECOFF
/* Handle the OSF/1 .comm pseudo quirks. */
return;
}
-#if OBJ_EVAX
- {
- /* Fill common area with zeros. */
- char *pfrag;
- segT current_seg = now_seg;
- subsegT current_subseg = now_subseg;
-
- subseg_set (bss_section, 1);
- frag_align (3, 0);
-
- symbolP->sy_frag = frag_now;
- pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP,
- temp, (char *)0);
-
- *pfrag = 0;
- S_SET_SEGMENT (symbolP, bss_section);
-
- subseg_set (current_seg, current_subseg);
- }
-#endif
-
if (S_GET_VALUE (symbolP))
{
if (S_GET_VALUE (symbolP) != (valueT) temp)
S_SET_EXTERNAL (symbolP);
}
-#ifndef OBJ_EVAX
know (symbolP->sy_frag == &zero_address_frag);
-#endif
demand_empty_rest_of_line ();
}
#endif /* ! OBJ_ELF */
-#if defined (OBJ_ECOFF) || defined (OBJ_EVAX)
+#ifdef OBJ_ECOFF
/* Handle the .rdata pseudo-op. This is like the usual one, but it
clears alpha_insn_label and restores auto alignment. */
/* Handle the .section pseudo-op. This is like the usual one, but it
clears alpha_insn_label and restores auto alignment. */
-static void
+static void
s_alpha_section (ignore)
int ignore;
{
alpha_current_align = 0;
}
-#endif
+#endif
#ifdef OBJ_EVAX
+
+/* Handle the section specific pseudo-op. */
+
static void
-s_alpha_link (ignore)
- int ignore;
+s_alpha_section (secid)
+ int secid;
{
int temp;
+#define EVAX_SECTION_COUNT 6
+ static char *section_name[EVAX_SECTION_COUNT+1] =
+ { "NULL", ".rdata", ".comm", ".link", ".ctors", ".dtors", ".lcomm" };
+ if ((secid <= 0) || (secid > EVAX_SECTION_COUNT))
+ {
+ as_fatal ("Unknown section directive");
+ demand_empty_rest_of_line ();
+ return;
+ }
temp = get_absolute_expression ();
- subseg_new (".link", 0);
+ subseg_new (section_name[secid], 0);
demand_empty_rest_of_line ();
alpha_insn_label = NULL;
alpha_auto_align_on = 1;
md_flush_pending_output ();
#endif
- frag_align (3, 0);
+ frag_align (3, 0, 0);
p = frag_more (16);
fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0);
fixp->fx_done = 1;
}
+/* Support for crash debug on vms. */
+
+static void
+s_alpha_name (ignore)
+ int ignore;
+{
+ register char *p;
+ expressionS exp;
+ segment_info_type *seginfo = seg_info (alpha_link_section);
+
+ if (now_seg != alpha_link_section)
+ {
+ as_bad (".name directive not in link (.link) section");
+ demand_empty_rest_of_line ();
+ return;
+ }
+
+ expression (&exp);
+ if (exp.X_op != O_symbol)
+ {
+ as_warn (".name directive has no symbol");
+ demand_empty_rest_of_line ();
+ return;
+ }
+
+ demand_empty_rest_of_line ();
+
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
+ frag_align (3, 0, 0);
+ p = frag_more (8);
+ seginfo->literal_pool_size += 8;
+
+ fix_new_exp (frag_now, p-frag_now->fr_literal, 8, &exp, 0, BFD_RELOC_64);
+
+ return;
+}
+
+
static void
s_alpha_linkage (ignore)
int ignore;
}
+static void
+s_alpha_code_address (ignore)
+ int ignore;
+{
+ expressionS exp;
+ char *p;
+
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
+ expression (&exp);
+ if (exp.X_op != O_symbol)
+ {
+ as_fatal ("No symbol after .code_address");
+ }
+ else
+ {
+ p = frag_more (8);
+ memset (p, 0, 8);
+ fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &exp, 0,\
+ BFD_RELOC_ALPHA_CODEADDR);
+ }
+ demand_empty_rest_of_line ();
+
+ return;
+}
+
+
static void
s_alpha_fp_save (ignore)
int ignore;
s_alpha_file (ignore)
int ignore;
{
- symbolS* s;
+ symbolS *s;
int length;
static char case_hack[32];
extern char *demand_copy_string PARAMS ((int *lenP));
- sprintf (case_hack, "<CASE:%01d%01d%01d%01d>",
- alpha_flag_hash_long_names,
- alpha_flag_show_after_trunc,
- alpha_flag_no_hash_mixed_case,
- alpha_vms_name_mapping);
+ sprintf (case_hack, "<CASE:%01d%01d>",
+ alpha_flag_hash_long_names, alpha_flag_show_after_trunc);
s = symbol_find_or_make (case_hack);
s->bsym->flags |= BSF_FILE;
alpha_insn_label = NULL;
}
\f
+
+#ifdef DEBUG1
+/* print token expression with alpha specific extension. */
+
+static void
+alpha_print_token(f, exp)
+ FILE *f;
+ const expressionS *exp;
+{
+ switch (exp->X_op)
+ {
+ case O_cpregister:
+ putc (',', f);
+ /* FALLTHRU */
+ case O_pregister:
+ putc ('(', f);
+ {
+ expressionS nexp = *exp;
+ nexp.X_op = O_register;
+ print_expr (f, &nexp);
+ }
+ putc (')', f);
+ break;
+ default:
+ print_expr (f, exp);
+ break;
+ }
+ return;
+}
+#endif
+\f
/* The target specific pseudo-ops which we support. */
const pseudo_typeS md_pseudo_table[] =
{
{"common", s_comm, 0}, /* is this used? */
-#ifndef OBJ_ELF
+#ifdef OBJ_ECOFF
{"comm", s_alpha_comm, 0}, /* osf1 compiler does this */
+ {"rdata", s_alpha_rdata, 0},
#endif
{"text", s_alpha_text, 0},
{"data", s_alpha_data, 0},
-#if defined (OBJ_ECOFF) || defined (OBJ_EVAX)
- {"rdata", s_alpha_rdata, 0},
-#endif
#ifdef OBJ_ECOFF
{"sdata", s_alpha_sdata, 0},
#endif
#endif
#ifdef OBJ_EVAX
{ "pdesc", s_alpha_pdesc, 0},
+ { "name", s_alpha_name, 0},
{ "linkage", s_alpha_linkage, 0},
+ { "code_address", s_alpha_code_address, 0},
{ "ent", s_alpha_ent, 0},
{ "frame", s_alpha_frame, 0},
{ "fp_save", s_alpha_fp_save, 0},
{ "mask", s_alpha_mask, 0},
{ "fmask", s_alpha_fmask, 0},
- { "link", s_alpha_link, 0},
{ "end", s_alpha_end, 0},
{ "file", s_alpha_file, 0},
+ { "rdata", s_alpha_section, 1},
+ { "comm", s_alpha_section, 2},
+ { "link", s_alpha_section, 3},
+ { "ctors", s_alpha_section, 4},
+ { "dtors", s_alpha_section, 5},
+ { "lcomm", s_alpha_section, 6},
#endif
{"gprel32", s_alpha_gprel32, 0},
{"t_floating", s_alpha_float_cons, 'd'},
no-op instructions. This will zero-fill, then nop-fill
with proper alignment. */
if (alpha_current_align < 2)
- frag_align (2, 0);
- frag_align_pattern (n, nop, sizeof nop);
+ frag_align (2, 0, 0);
+ frag_align_pattern (n, nop, sizeof nop, 0);
}
else
- frag_align (n, 0);
+ frag_align (n, 0, 0);
}
else
- frag_align (n, *pfill);
+ frag_align (n, *pfill, 0);
alpha_current_align = n;
-/* tc-arm.c All the arm specific stuff in one convenient, huge,
- slow to compile, easy to find file.
+/* tc-arm.c -- Assemble for the ARM
+ Copyright (C) 1994, 95, 96, 1997 Free Software Foundation, Inc.
Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
Modified by David Taylor (dtaylor@armltd.co.uk)
- Copyright (C) 1994, 1995 Free Software Foundation, Inc.
-
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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. */
#include <ctype.h>
#include <string.h>
#define ARM_1 0x00000001
#define ARM_2 0x00000002
#define ARM_3 0x00000004
-#define ARM_250 0x00000004 /* ARM3 instruction set */
+#define ARM_250 ARM_3
#define ARM_6 0x00000008
-#define ARM_7 0x00000008
+#define ARM_7 ARM_6 /* same core instruction set */
/* The following bitmasks control CPU extensions (ARM7 onwards): */
#define ARM_LONGMUL 0x00000010 /* allow long multiplies */
-#define ARM_HALFWORD 0x00000020 /* allow ARM 16bit memory transfers */
+#define ARM_ARCH4 0x00000020
+#define ARM_THUMB ARM_ARCH4
/* Some useful combinations: */
#define ARM_ANY 0x00ffffff
CONST char FLT_CHARS[] = "rRsSfFdDxXeEpP";
-const int md_reloc_size = 8; /* Size of relocation record */
+CONST int md_reloc_size = 8; /* Size of relocation record */
+
+static int thumb_mode = 0; /* non-zero if assembling thumb instructions */
+
+typedef struct arm_fix
+{
+ int thumb_mode;
+} arm_fix_data;
struct arm_it
{
CONST char *error;
unsigned long instruction;
int suffix;
+ int size;
struct
{
bfd_reloc_code_real_type type;
#define CP_T_UD 0x00800000
#define CP_T_WB 0x00200000
+#define CONDS_BIT (0x00100000)
+#define LOAD_BIT (0x00100000)
#define TRANS_BIT (0x00200000)
struct asm_cond
{"nv", 0xf0000000}
};
-
+/* Warning: If the top bit of the set_bits is set, then the standard
+ instruction bitmask is ignored, and the new bitmask is taken from
+ the set_bits: */
struct asm_flg
{
CONST char *template; /* Basic flag string */
unsigned long set_bits; /* Bits to set */
- unsigned long variants; /* Which CPU variants this exists for */
};
static CONST struct asm_flg s_flag[] =
{
- {"s", 0x00100000, ARM_ANY},
- {NULL, 0, 0}
+ {"s", CONDS_BIT},
+ {NULL, 0}
+};
+
+static CONST struct asm_flg ldr_flags[] =
+{
+ {"b", 0x00400000},
+ {"t", TRANS_BIT},
+ {"bt", 0x00400000 | TRANS_BIT},
+ {"h", 0x801000b0},
+ {"sh", 0x801000f0},
+ {"sb", 0x801000d0},
+ {NULL, 0}
};
-static CONST struct asm_flg ldst_flags[] =
+static CONST struct asm_flg str_flags[] =
{
- {"b", 0x00400000, ARM_ANY},
- {"t", TRANS_BIT, ARM_ANY},
- {"bt", 0x00400000 | TRANS_BIT, ARM_ANY},
- {"h", 0x00000020, ARM_HALFWORD},
- {"sb", 0x00000040, ARM_HALFWORD},
- {"sh", 0x00000060, ARM_HALFWORD},
- {NULL, 0, 0},
+ {"b", 0x00400000},
+ {"t", TRANS_BIT},
+ {"bt", 0x00400000 | TRANS_BIT},
+ {"h", 0x800000b0},
+ {NULL, 0}
};
static CONST struct asm_flg byte_flag[] =
{
- {"b", 0x00400000, ARM_3UP},
- {NULL, 0, 0}
+ {"b", 0x00400000},
+ {NULL, 0}
};
static CONST struct asm_flg cmp_flags[] =
{
- {"s", 0x00100000, ARM_ANY},
- {"p", 0x0010f000, ARM_ANY},
- {NULL, 0, 0}
+ {"s", CONDS_BIT},
+ {"p", 0x0010f000},
+ {NULL, 0}
};
static CONST struct asm_flg ldm_flags[] =
{
- {"ed", 0x01800000, ARM_ANY},
- {"fd", 0x00800000, ARM_ANY},
- {"ea", 0x01000000, ARM_ANY},
- {"fa", 0x08000000, ARM_ANY},
- {"ib", 0x01800000, ARM_ANY},
- {"ia", 0x00800000, ARM_ANY},
- {"db", 0x01000000, ARM_ANY},
- {"da", 0x08000000, ARM_ANY},
- {NULL, 0, 0}
+ {"ed", 0x01800000},
+ {"fd", 0x00800000},
+ {"ea", 0x01000000},
+ {"fa", 0x08000000},
+ {"ib", 0x01800000},
+ {"ia", 0x00800000},
+ {"db", 0x01000000},
+ {"da", 0x08000000},
+ {NULL, 0}
};
static CONST struct asm_flg stm_flags[] =
{
- {"ed", 0x08000000, ARM_ANY},
- {"fd", 0x01000000, ARM_ANY},
- {"ea", 0x00800000, ARM_ANY},
- {"fa", 0x01800000, ARM_ANY},
- {"ib", 0x01800000, ARM_ANY},
- {"ia", 0x00800000, ARM_ANY},
- {"db", 0x01000000, ARM_ANY},
- {"da", 0x08000000, ARM_ANY},
- {NULL, 0, 0}
+ {"ed", 0x08000000},
+ {"fd", 0x01000000},
+ {"ea", 0x00800000},
+ {"fa", 0x01800000},
+ {"ib", 0x01800000},
+ {"ia", 0x00800000},
+ {"db", 0x01000000},
+ {"da", 0x08000000},
+ {NULL, 0}
};
static CONST struct asm_flg lfm_flags[] =
{
- {"fd", 0x00800000, FPU_MEMMULTI},
- {"ea", 0x01000000, FPU_MEMMULTI},
- {NULL, 0, 0}
+ {"fd", 0x00800000},
+ {"ea", 0x01000000},
+ {NULL, 0}
};
static CONST struct asm_flg sfm_flags[] =
{
- {"fd", 0x01000000, FPU_MEMMULTI},
- {"ea", 0x00800000, FPU_MEMMULTI},
- {NULL, 0, 0}
+ {"fd", 0x01000000},
+ {"ea", 0x00800000},
+ {NULL, 0}
};
static CONST struct asm_flg round_flags[] =
{
- {"p", 0x00000020, FPU_ALL},
- {"m", 0x00000040, FPU_ALL},
- {"z", 0x00000060, FPU_ALL},
- {NULL, 0, 0}
+ {"p", 0x00000020},
+ {"m", 0x00000040},
+ {"z", 0x00000060},
+ {NULL, 0}
+};
+
+/* The implementation of the FIX instruction is broken on some assemblers,
+ in that it accepts a precision specifier as well as a rounding specifier,
+ despite the fact that this is meaningless. To be more compatible, we
+ accept it as well, though of course it does not set any bits. */
+static CONST struct asm_flg fix_flags[] =
+{
+ {"p", 0x00000020},
+ {"m", 0x00000040},
+ {"z", 0x00000060},
+ {"sp", 0x00000020},
+ {"sm", 0x00000040},
+ {"sz", 0x00000060},
+ {"dp", 0x00000020},
+ {"dm", 0x00000040},
+ {"dz", 0x00000060},
+ {"ep", 0x00000020},
+ {"em", 0x00000040},
+ {"ez", 0x00000060},
+ {NULL, 0}
};
static CONST struct asm_flg except_flag[] =
{
- {"e", 0x00400000, FPU_ALL},
- {NULL, 0, 0}
+ {"e", 0x00400000},
+ {NULL, 0}
};
static CONST struct asm_flg cplong_flag[] =
{
- {"l", 0x00400000, ARM_2UP},
- {NULL, 0, 0}
+ {"l", 0x00400000},
+ {NULL, 0}
};
struct asm_psr
static void do_mrs PARAMS ((char *operands, unsigned long flags));
/* ARM 7M */
static void do_mull PARAMS ((char *operands, unsigned long flags));
+/* ARM THUMB */
+static void do_bx PARAMS ((char *operands, unsigned long flags));
/* Coprocessor Instructions */
static void do_cdp PARAMS ((char *operands, unsigned long flags));
static int arm_psr_parse PARAMS ((char **ccp));
/* ARM instructions take 4bytes in the object file, Thumb instructions
- take 2. The assembler defaults to ARM code generation: */
-static int insn_size = 4;
+ take 2: */
+#define INSN_SIZE 4
/* LONGEST_INST is the longest basic instruction name without conditions or
* flags.
- * ARM7DM has 4 of length 5
+ * ARM7M has 4 of length 5
*/
#define LONGEST_INST 5
{"cmn", 0x01600000, NULL, cmp_flags, ARM_ANY, do_cmp},
{"mov", 0x01a00000, NULL, s_flag, ARM_ANY, do_mov},
{"mvn", 0x01e00000, NULL, s_flag, ARM_ANY, do_mov},
- {"str", 0x04000000, NULL, ldst_flags, ARM_ANY, do_ldst},
- {"ldr", 0x04100000, NULL, ldst_flags, ARM_ANY, do_ldst},
+ {"str", 0x04000000, NULL, str_flags, ARM_ANY, do_ldst},
+ {"ldr", 0x04100000, NULL, ldr_flags, ARM_ANY, do_ldst},
{"stm", 0x08000000, NULL, stm_flags, ARM_ANY, do_ldmstm},
{"ldm", 0x08100000, NULL, ldm_flags, ARM_ANY, do_ldmstm},
{"swi", 0x0f000000, NULL, NULL, ARM_ANY, do_swi},
- {"bl", 0x0b000000, NULL, NULL, ARM_ANY, do_branch},
- {"b", 0x0a000000, NULL, NULL, ARM_ANY, do_branch},
+ {"bl", 0x0bfffffe, NULL, NULL, ARM_ANY, do_branch},
+ {"b", 0x0afffffe, NULL, NULL, ARM_ANY, do_branch},
/* Pseudo ops */
{"adr", 0x028f0000, NULL, NULL, ARM_ANY, do_adr},
{"smlal", 0x00e00090, NULL, s_flag, ARM_LONGMUL, do_mull},
{"umlal", 0x00a00090, NULL, s_flag, ARM_LONGMUL, do_mull},
+/* ARM THUMB interworking */
+ {"bx", 0x012fff10, NULL, NULL, ARM_THUMB, do_bx},
+
/* Floating point instructions */
{"wfs", 0x0e200110, NULL, NULL, FPU_ALL, do_fp_ctrl},
{"rfs", 0x0e300110, NULL, NULL, FPU_ALL, do_fp_ctrl},
{"cmfe", 0x0ed0f110, NULL, NULL, FPU_ALL, do_fp_cmp},
{"cnfe", 0x0ef0f110, NULL, NULL, FPU_ALL, do_fp_cmp},
{"flt", 0x0e000110, "sde", round_flags, FPU_ALL, do_fp_from_reg},
- {"fix", 0x0e100110, NULL, round_flags, FPU_ALL, do_fp_to_reg},
+ {"fix", 0x0e100110, NULL, fix_flags, FPU_ALL, do_fp_to_reg},
/* Generic copressor instructions */
{"cdp", 0x0e000000, NULL, NULL, ARM_2UP, do_cdp},
#define OPCODE_BIC 14
#define OPCODE_MVN 15
+static void do_t_arit PARAMS ((char *operands));
+static void do_t_add PARAMS ((char *operands));
+static void do_t_asr PARAMS ((char *operands));
+static void do_t_branch PARAMS ((char *operands));
+static void do_t_bx PARAMS ((char *operands));
+static void do_t_compare PARAMS ((char *operands));
+static void do_t_ldmstm PARAMS ((char *operands));
+static void do_t_ldr PARAMS ((char *operands));
+static void do_t_ldrb PARAMS ((char *operands));
+static void do_t_ldrh PARAMS ((char *operands));
+static void do_t_lds PARAMS ((char *operands));
+static void do_t_lsl PARAMS ((char *operands));
+static void do_t_lsr PARAMS ((char *operands));
+static void do_t_mov PARAMS ((char *operands));
+static void do_t_push_pop PARAMS ((char *operands));
+static void do_t_str PARAMS ((char *operands));
+static void do_t_strb PARAMS ((char *operands));
+static void do_t_strh PARAMS ((char *operands));
+static void do_t_sub PARAMS ((char *operands));
+static void do_t_swi PARAMS ((char *operands));
+static void do_t_adr PARAMS ((char *operands));
+
+#define T_OPCODE_MUL 0x4340
+#define T_OPCODE_TST 0x4200
+#define T_OPCODE_CMN 0x42c0
+#define T_OPCODE_NEG 0x4240
+#define T_OPCODE_MVN 0x43c0
+
+#define T_OPCODE_ADD_R3 0x1800
+#define T_OPCODE_SUB_R3 0x1a00
+#define T_OPCODE_ADD_HI 0x4400
+#define T_OPCODE_ADD_ST 0xb000
+#define T_OPCODE_SUB_ST 0xb080
+#define T_OPCODE_ADD_SP 0xa800
+#define T_OPCODE_ADD_PC 0xa000
+#define T_OPCODE_ADD_I8 0x3000
+#define T_OPCODE_SUB_I8 0x3800
+#define T_OPCODE_ADD_I3 0x1c00
+#define T_OPCODE_SUB_I3 0x1e00
+
+#define T_OPCODE_ASR_R 0x4100
+#define T_OPCODE_LSL_R 0x4080
+#define T_OPCODE_LSR_R 0x40c0
+#define T_OPCODE_ASR_I 0x1000
+#define T_OPCODE_LSL_I 0x0000
+#define T_OPCODE_LSR_I 0x0800
+
+#define T_OPCODE_MOV_I8 0x2000
+#define T_OPCODE_CMP_I8 0x2800
+#define T_OPCODE_CMP_LR 0x4280
+#define T_OPCODE_MOV_HR 0x4600
+#define T_OPCODE_CMP_HR 0x4500
+
+#define T_OPCODE_LDR_PC 0x4800
+#define T_OPCODE_LDR_SP 0x9800
+#define T_OPCODE_STR_SP 0x9000
+#define T_OPCODE_LDR_IW 0x6800
+#define T_OPCODE_STR_IW 0x6000
+#define T_OPCODE_LDR_IH 0x8800
+#define T_OPCODE_STR_IH 0x8000
+#define T_OPCODE_LDR_IB 0x7800
+#define T_OPCODE_STR_IB 0x7000
+#define T_OPCODE_LDR_RW 0x5800
+#define T_OPCODE_STR_RW 0x5000
+#define T_OPCODE_LDR_RH 0x5a00
+#define T_OPCODE_STR_RH 0x5200
+#define T_OPCODE_LDR_RB 0x5c00
+#define T_OPCODE_STR_RB 0x5400
+
+#define T_OPCODE_PUSH 0xb400
+#define T_OPCODE_POP 0xbc00
+
+#define T_OPCODE_BRANCH 0xe7fe
+
+static int thumb_reg PARAMS ((char **str, int hi_lo));
+
+#define THUMB_SIZE 2 /* Size of thumb instruction */
+#define THUMB_REG_LO 0x1
+#define THUMB_REG_HI 0x2
+#define THUMB_REG_ANY 0x3
+
+#define THUMB_H1 0x0080
+#define THUMB_H2 0x0040
+
+#define THUMB_ASR 0
+#define THUMB_LSL 1
+#define THUMB_LSR 2
+
+#define THUMB_MOVE 0
+#define THUMB_COMPARE 1
+
+#define THUMB_LOAD 0
+#define THUMB_STORE 1
+
+#define THUMB_PP_PC_LR 0x0100
+
+/* These three are used for immediate shifts, do not alter */
+#define THUMB_WORD 2
+#define THUMB_HALFWORD 1
+#define THUMB_BYTE 0
+
+struct thumb_opcode
+{
+ CONST char *template; /* Basic string to match */
+ unsigned long value; /* Basic instruction code */
+ int size;
+ void (*parms)(); /* Function to call to parse args */
+};
+
+static CONST struct thumb_opcode tinsns[] =
+{
+ {"adc", 0x4140, 2, do_t_arit},
+ {"add", 0x0000, 2, do_t_add},
+ {"and", 0x4000, 2, do_t_arit},
+ {"asr", 0x0000, 2, do_t_asr},
+ {"b", T_OPCODE_BRANCH, 2, do_t_branch},
+ {"beq", 0xd0fe, 2, do_t_branch},
+ {"bne", 0xd1fe, 2, do_t_branch},
+ {"bcs", 0xd2fe, 2, do_t_branch},
+ {"bhs", 0xd2fe, 2, do_t_branch},
+ {"bcc", 0xd3fe, 2, do_t_branch},
+ {"bul", 0xd3fe, 2, do_t_branch},
+ {"blo", 0xd3fe, 2, do_t_branch},
+ {"bmi", 0xd4fe, 2, do_t_branch},
+ {"bpl", 0xd5fe, 2, do_t_branch},
+ {"bvs", 0xd6fe, 2, do_t_branch},
+ {"bvc", 0xd7fe, 2, do_t_branch},
+ {"bhi", 0xd8fe, 2, do_t_branch},
+ {"bls", 0xd9fe, 2, do_t_branch},
+ {"bge", 0xdafe, 2, do_t_branch},
+ {"blt", 0xdbfe, 2, do_t_branch},
+ {"bgt", 0xdcfe, 2, do_t_branch},
+ {"ble", 0xddfe, 2, do_t_branch},
+ {"bic", 0x4380, 2, do_t_arit},
+ {"bl", 0xf7fffffe, 4, do_t_branch},
+ {"bx", 0x4700, 2, do_t_bx},
+ {"cmn", T_OPCODE_CMN, 2, do_t_arit},
+ {"cmp", 0x0000, 2, do_t_compare},
+ {"eor", 0x4040, 2, do_t_arit},
+ {"ldmia", 0xc800, 2, do_t_ldmstm},
+ {"ldr", 0x0000, 2, do_t_ldr},
+ {"ldrb", 0x0000, 2, do_t_ldrb},
+ {"ldrh", 0x0000, 2, do_t_ldrh},
+ {"ldrsb", 0x5600, 2, do_t_lds},
+ {"ldrsh", 0x5e00, 2, do_t_lds},
+ {"ldsb", 0x5600, 2, do_t_lds},
+ {"ldsh", 0x5e00, 2, do_t_lds},
+ {"lsl", 0x0000, 2, do_t_lsl},
+ {"lsr", 0x0000, 2, do_t_lsr},
+ {"mov", 0x0000, 2, do_t_mov},
+ {"mul", T_OPCODE_MUL, 2, do_t_arit},
+ {"mvn", T_OPCODE_MVN, 2, do_t_arit},
+ {"neg", T_OPCODE_NEG, 2, do_t_arit},
+ {"orr", 0x4300, 2, do_t_arit},
+ {"pop", 0xbc00, 2, do_t_push_pop},
+ {"push", 0xb400, 2, do_t_push_pop},
+ {"ror", 0x41c0, 2, do_t_arit},
+ {"sbc", 0x4180, 2, do_t_arit},
+ {"stmia", 0xc000, 2, do_t_ldmstm},
+ {"str", 0x0000, 2, do_t_str},
+ {"strb", 0x0000, 2, do_t_strb},
+ {"strh", 0x0000, 2, do_t_strh},
+ {"swi", 0xdf00, 2, do_t_swi},
+ {"sub", 0x0000, 2, do_t_sub},
+ {"tst", T_OPCODE_TST, 2, do_t_arit},
+ /* Pseudo ops: */
+ {"adr", 0x0000, 2, do_t_adr},
+ {"nop", 0x0000, 2, do_nop},
+};
+
struct reg_entry
{
CONST char *name;
#define fp_register(reg) ((reg) >= 16 && (reg) <= 23)
#define REG_PC 15
+#define REG_LR 14
+#define REG_SP 13
/* These are the standard names; Users can add aliases with .req */
static CONST struct reg_entry reg_table[] =
{
/* Processor Register Numbers */
- {"r0", 0}, {"r1", 1}, {"r2", 2}, {"r3", 3},
- {"r4", 4}, {"r5", 5}, {"r6", 6}, {"r7", 7},
- {"r8", 8}, {"r9", 9}, {"r10", 10}, {"r11", 11},
- {"r12", 12}, {"r13", 13}, {"r14", 14}, {"r15", REG_PC},
+ {"r0", 0}, {"r1", 1}, {"r2", 2}, {"r3", 3},
+ {"r4", 4}, {"r5", 5}, {"r6", 6}, {"r7", 7},
+ {"r8", 8}, {"r9", 9}, {"r10", 10}, {"r11", 11},
+ {"r12", 12}, {"r13", REG_SP},{"r14", REG_LR},{"r15", REG_PC},
/* APCS conventions */
- {"a1", 0}, {"a2", 1}, {"a3", 2}, {"a4", 3},
- {"v1", 4}, {"v2", 5}, {"v3", 6}, {"v4", 7}, {"v5", 8},
- {"v6", 9}, {"sb", 9}, {"v7", 10}, {"sl", 10},
- {"fp", 11}, {"ip", 12}, {"sp", 13}, {"lr", 14}, {"pc", REG_PC},
+ {"a1", 0}, {"a2", 1}, {"a3", 2}, {"a4", 3},
+ {"v1", 4}, {"v2", 5}, {"v3", 6}, {"v4", 7}, {"v5", 8},
+ {"v6", 9}, {"sb", 9}, {"v7", 10}, {"sl", 10},
+ {"fp", 11}, {"ip", 12}, {"sp", REG_SP},{"lr", REG_LR},{"pc", REG_PC},
/* FP Registers */
{"f0", 16}, {"f1", 17}, {"f2", 18}, {"f3", 19},
{"f4", 20}, {"f5", 21}, {"f6", 22}, {"f7", 23},
static CONST char *bad_pc = "r15 not allowed here";
static struct hash_control *arm_ops_hsh = NULL;
+static struct hash_control *arm_tops_hsh = NULL;
static struct hash_control *arm_cond_hsh = NULL;
static struct hash_control *arm_shift_hsh = NULL;
static struct hash_control *arm_reg_hsh = NULL;
static void s_bss PARAMS ((int));
static void s_even PARAMS ((int));
static void s_ltorg PARAMS ((int));
+static void s_arm PARAMS ((int));
+static void s_thumb PARAMS ((int));
+static void s_code PARAMS ((int));
static int my_get_expression PARAMS ((expressionS *, char **));
{"req", s_req, 0}, /* Never called becasue '.req' does not start line */
{"bss", s_bss, 0},
{"align", s_align, 0},
+ {"arm", s_arm, 0},
+ {"thumb", s_thumb, 0},
+ {"code", s_code, 0},
{"even", s_even, 0},
{"ltorg", s_ltorg, 0},
{"pool", s_ltorg, 0},
}
/* Can't use symbol_new here, so have to create a symbol and them at
- a later datete assign iot a value. Thats what these functions do */
+ a later date assign it a value. Thats what these functions do */
static void
symbol_locate (symbolP, name, segment, valu, frag)
symbolS *symbolP;
int ignore;
{
if (!need_pass_2) /* Never make frag if expect extra pass. */
- frag_align (1, 0);
+ frag_align (1, 0, 0);
record_alignment (now_seg, 1);
demand_empty_rest_of_line ();
}
/* Align pool as you have word accesses */
/* Only make a frag if we have to ... */
if (!need_pass_2)
- frag_align (2, 0);
+ frag_align (2, 0, 0);
record_alignment (now_seg, 2);
{
/* Only make a frag if we HAVE to ... */
if (power && !need_pass_2)
- frag_align (power, fill);
+ frag_align (power, fill, 0);
record_alignment (now_seg, power);
}
/* Only make a frag if we HAVE to. . . */
if (temp && !need_pass_2)
- frag_align (temp, (int) temp_fill);
+ frag_align (temp, (int) temp_fill, 0);
demand_empty_rest_of_line ();
record_alignment (now_seg, temp);
}
+static void
+opcode_select (width)
+ int width;
+{
+ switch (width)
+ {
+ case 16:
+ if (! thumb_mode)
+ {
+ if (! (cpu_variant & ARM_THUMB))
+ as_bad ("selected processor does not support THUMB opcodes");
+ thumb_mode = 1;
+ /* No need to force the alignment, since we will have been
+ coming from ARM mode, which is word-aligned. */
+ record_alignment (now_seg, 1);
+ }
+ break;
+
+ case 32:
+ if (thumb_mode)
+ {
+ if ((cpu_variant & ARM_ANY) == ARM_THUMB)
+ as_bad ("selected processor does not support ARM opcodes");
+ thumb_mode = 0;
+ if (!need_pass_2)
+ frag_align (2, 0, 0);
+ record_alignment (now_seg, 1);
+ }
+ break;
+
+ default:
+ as_bad ("invalid instruction size selected (%d)", width);
+ }
+}
+
+static void
+s_arm (ignore)
+ int ignore;
+{
+ opcode_select (32);
+ demand_empty_rest_of_line ();
+}
+
+static void
+s_thumb (ignore)
+ int ignore;
+{
+ opcode_select (16);
+ demand_empty_rest_of_line ();
+}
+
+static void
+s_code (unused)
+ int unused;
+{
+ register int temp;
+
+ temp = get_absolute_expression ();
+ switch (temp)
+ {
+ case 16:
+ case 32:
+ opcode_select(temp);
+ break;
+
+ default:
+ as_bad ("invalid operand to .code directive (%d)", temp);
+ }
+}
+
static void
end_of_line (str)
char *str;
*p = c;
if (shft)
{
- if (!strcmp (*str, "rrx"))
+ if (!strcmp (*str, "rrx")
+ || !strcmp (*str, "RRX"))
{
*str = p;
inst.instruction |= shft->value;
return FAIL;
/* Validate some simple #expressions */
- if (! inst.reloc.exp.X_add_symbol)
+ if (inst.reloc.exp.X_op == O_constant)
{
- int num = inst.reloc.exp.X_add_number;
- if (num < 0 || num > 32
- || (num == 32
- && (shft->value == 0 || shft->value == 0x60)))
+ unsigned num = inst.reloc.exp.X_add_number;
+
+ /* Reject operations greater than 32, or lsl #32 */
+ if (num > 32 || (num == 32 && shft->value == 0))
{
inst.error = "Invalid immediate shift";
return FAIL;
char *str;
unsigned long flags;
{
- /* This is a pseudo-op of the form "adr rd, label" to be converted into
- a relative address of the form add rd, pc, #label-.-8 */
+ /* This is a pseudo-op of the form "adr rd, label" to be converted
+ into a relative address of the form "add rd, pc, #label-.-8" */
while (*str == ' ')
str++;
inst.instruction |= flags;
if ((flags & 0x0000f000) == 0)
- inst.instruction |= 0x00100000;
+ inst.instruction |= CONDS_BIT;
end_of_line (str);
return;
if (hwse)
inst.instruction |= add;
else
- inst.instruction |= add | OFFSET_REG;
+ {
+ inst.instruction |= add | OFFSET_REG;
+ if (skip_past_comma (str) == SUCCESS)
+ return decode_shift (str, SHIFT_RESTRICT);
+ }
- /* Shifts are not allowed in the halfword and signextension
- forms of single memory transfers: */
- if (!hwse && skip_past_comma (str) == SUCCESS)
- return decode_shift (str, SHIFT_RESTRICT);
return SUCCESS;
}
}
unsigned long flags;
{
int halfword = 0;
- int signextend = 0;
int pre_inc = 0;
int conflict_reg;
int value;
/* This is not ideal, but it is the simplest way of dealing with the
- ARM7T extension instructions (since they use a different
+ ARM7T halfword instructions (since they use a different
encoding, but the same mnemonic): */
- halfword = flags & 0x00000020;
- signextend = flags & 0x00000040;
- if (halfword || signextend)
+ if (halfword = ((flags & 0x80000000) != 0))
{
/* This is actually a load/store of a halfword, or a
signed-extension load */
- inst.instruction = (inst.instruction & COND_MASK)
- | 0x00000090
- | (inst.instruction & 0x00100000);
- if (signextend && !(inst.instruction & 0x00100000))
+ if ((cpu_variant & ARM_ARCH4) == 0)
{
- inst.error = "Sign-extension not applicable to store instructions";
- return;
+ inst.error
+ = "Processor does not support halfwords or signed bytes\n";
+ return;
}
+
+ inst.instruction = (inst.instruction & COND_MASK)
+ | (flags & ~COND_MASK);
+
+ flags = 0;
}
while (*str == ' ')
}
conflict_reg = (((conflict_reg == reg)
- && (inst.instruction & 0x00100000))
+ && (inst.instruction & LOAD_BIT))
? 1 : 0);
while (*str == ' ')
if (skip_past_comma (&str) == SUCCESS)
{
/* [Rn],... (post inc) */
- if (ldst_extend (&str, halfword | signextend) == FAIL)
+ if (ldst_extend (&str, halfword) == FAIL)
return;
if (conflict_reg)
as_warn ("destination register same as write-back base\n");
else
{
/* [Rn] */
- if (halfword | signextend)
+ if (halfword)
inst.instruction |= HWOFFSET_IMM;
while (*str == ' ')
}
pre_inc = 1;
- if (ldst_extend (&str, halfword | signextend) == FAIL)
+ if (ldst_extend (&str, halfword) == FAIL)
return;
while (*str == ' ')
if (*str == '!')
{
if (conflict_reg)
- as_warn ("destination register same as write-back base\n");
+ as_tsktsk ("destination register same as write-back base\n");
str++;
inst.instruction |= WRITE_BACK;
}
}
/* Change the instruction exp to point to the pool */
- if (halfword || signextend)
+ if (halfword)
{
inst.instruction |= HWOFFSET_IMM;
inst.reloc.type = BFD_RELOC_ARM_HWLITERAL;
if (my_get_expression (&inst.reloc.exp, &str))
return;
- if (halfword || signextend)
+ if (halfword)
{
inst.instruction |= HWOFFSET_IMM;
inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
return;
}
-static void
-do_ldmstm (str, flags)
- char *str;
- unsigned long flags;
+static long
+reg_list (strp)
+ char **strp;
{
- int base_reg;
+ char *str = *strp;
+ long range = 0;
+ int another_range;
- while (*str == ' ')
- str++;
-
- if ((base_reg = reg_required_here (&str, 16)) == FAIL)
+ /* We come back here if we get ranges concatenated by '+' or '|' */
+ do
{
- if (!inst.error)
- inst.error = bad_args;
- return;
- }
+ another_range = 0;
- if (base_reg == REG_PC)
- {
- inst.error = "r15 not allowed as base register";
- return;
- }
+ if (*str == '{')
+ {
+ int in_range = 0;
+ int cur_reg = -1;
+
+ str++;
+ do
+ {
+ int reg;
+
+ while (*str == ' ')
+ str++;
- while (*str == ' ')
- str++;
- if (*str == '!')
- {
- flags |= WRITE_BACK;
- str++;
- }
+ if ((reg = arm_reg_parse (&str)) == FAIL || !int_register (reg))
+ {
+ inst.error = "Register expected";
+ return FAIL;
+ }
- if (skip_past_comma (&str) == FAIL)
- {
- inst.error = bad_args;
- return;
- }
+ if (in_range)
+ {
+ int i;
+
+ if (reg <= cur_reg)
+ {
+ inst.error = "Bad range in register list";
+ return FAIL;
+ }
- /* We come back here if we get ranges concatenated by '+' or '|' */
- another_range:
- if (*str == '{')
- {
- int in_range = 0;
- int cur_reg = -1;
-
- str++;
- do
- {
- int reg;
-
+ for (i = cur_reg + 1; i < reg; i++)
+ {
+ if (range & (1 << i))
+ as_tsktsk
+ ("Warning: Duplicated register (r%d) in register list",
+ i);
+ else
+ range |= 1 << i;
+ }
+ in_range = 0;
+ }
+
+ if (range & (1 << reg))
+ as_tsktsk ("Warning: Duplicated register (r%d) in register list",
+ reg);
+ else if (reg <= cur_reg)
+ as_tsktsk ("Warning: Register range not in ascending order");
+
+ range |= 1 << reg;
+ cur_reg = reg;
+ } while (skip_past_comma (&str) != FAIL
+ || (in_range = 1, *str++ == '-'));
+ str--;
while (*str == ' ')
str++;
- if ((reg = arm_reg_parse (&str)) == FAIL || !int_register (reg))
+ if (*str++ != '}')
{
- inst.error = "Register expected";
- return;
+ inst.error = "Missing `}'";
+ return FAIL;
}
+ }
+ else
+ {
+ expressionS expr;
+
+ if (my_get_expression (&expr, &str))
+ return FAIL;
- if (in_range)
+ if (expr.X_op == O_constant)
{
- int i;
-
- if (reg <= cur_reg)
+ if (expr.X_add_number
+ != (expr.X_add_number & 0x0000ffff))
{
- inst.error = "Bad range in register list";
- return;
+ inst.error = "invalid register mask";
+ return FAIL;
}
- for (i = cur_reg + 1; i < reg; i++)
+ if ((range & expr.X_add_number) != 0)
{
- if (flags & (1 << i))
- as_tsktsk
- ("Warning: Duplicated register (r%d) in register list",
- i);
- else
- flags |= 1 << i;
+ int regno = range & expr.X_add_number;
+
+ regno &= -regno;
+ regno = (1 << regno) - 1;
+ as_tsktsk
+ ("Warning: Duplicated register (r%d) in register list",
+ regno);
+ }
+
+ range |= expr.X_add_number;
+ }
+ else
+ {
+ if (inst.reloc.type != 0)
+ {
+ inst.error = "expression too complex";
+ return FAIL;
}
- in_range = 0;
+
+ memcpy (&inst.reloc.exp, &expr, sizeof (expressionS));
+ inst.reloc.type = BFD_RELOC_ARM_MULTI;
+ inst.reloc.pc_rel = 0;
}
+ }
- if (flags & (1 << reg))
- as_tsktsk ("Warning: Duplicated register (r%d) in register list",
- reg);
- else if (reg <= cur_reg)
- as_tsktsk ("Warning: Register range not in ascending order");
-
- flags |= 1 << reg;
- cur_reg = reg;
- } while (skip_past_comma (&str) != FAIL
- || (in_range = 1, *str++ == '-'));
- str--;
while (*str == ' ')
str++;
- if (*str++ != '}')
+ if (*str == '|' || *str == '+')
{
- inst.error = "Missing `}'";
- return;
+ str++;
+ another_range = 1;
}
- }
- else
- {
- expressionS expr;
+ } while (another_range);
- if (my_get_expression (&expr, &str))
- return;
-
- if (expr.X_op == O_constant)
- {
- if (expr.X_add_number
- != (expr.X_add_number & 0x0000ffff))
- {
- inst.error = "invalid register mask";
- return;
- }
+ *strp = str;
+ return range;
+}
- if ((flags & expr.X_add_number) != 0)
- {
- int regno = flags & expr.X_add_number;
+static void
+do_ldmstm (str, flags)
+ char *str;
+ unsigned long flags;
+{
+ int base_reg;
+ long range;
- regno &= -regno;
- regno = (1 << regno) - 1;
- as_tsktsk ("Warning: Duplicated register (r%d) in register list",
- regno);
- }
+ while (*str == ' ')
+ str++;
- flags |= expr.X_add_number;
- }
- else
- {
- if (inst.reloc.type != 0)
- {
- inst.error = "expression too complex";
- return;
- }
+ if ((base_reg = reg_required_here (&str, 16)) == FAIL)
+ {
+ if (!inst.error)
+ inst.error = bad_args;
+ return;
+ }
- memcpy (&inst.reloc.exp, &expr, sizeof (expressionS));
- inst.reloc.type = BFD_RELOC_ARM_MULTI;
- inst.reloc.pc_rel = 0;
- }
+ if (base_reg == REG_PC)
+ {
+ inst.error = "r15 not allowed as base register";
+ return;
}
while (*str == ' ')
str++;
-
- if (*str == '|' || *str == '+')
+ if (*str == '!')
{
+ flags |= WRITE_BACK;
str++;
- goto another_range;
+ }
+
+ if (skip_past_comma (&str) == FAIL
+ || (range = reg_list (&str)) == FAIL)
+ {
+ if (! inst.error)
+ inst.error = bad_args;
+ return;
}
if (*str == '^')
str++;
flags |= MULTI_SET_PSR;
}
- inst.instruction |= flags;
+
+ inst.instruction |= flags | range;
end_of_line (str);
return;
}
return;
inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
inst.reloc.pc_rel = 1;
- inst.instruction |= flags | 0x00fffffe; /* PC-rel adjust */
+ end_of_line (str);
+ return;
+}
+
+static void
+do_bx (str, flags)
+ char *str;
+ unsigned long flags;
+{
+ int reg;
+
+ while (*str == ' ')
+ str++;
+
+ if ((reg = reg_required_here (&str, 0)) == FAIL)
+ return;
+
+ if (reg == REG_PC)
+ as_tsktsk ("Use of r15 in bx has undefined behaviour");
+
end_of_line (str);
return;
}
return;
}
-static void
-insert_reg (entry)
- int entry;
+/* Thumb specific routines */
+
+/* Parse and validate that a register is of the right form, this saves
+ repeated checking of this information in many similar cases.
+ Unlike the 32-bit case we do not insert the register into the opcode
+ here, since the position is often unknown until the full instruction
+ has been parsed. */
+static int
+thumb_reg (strp, hi_lo)
+ char **strp;
+ int hi_lo;
{
- int len = strlen (reg_table[entry].name) + 2;
- char *buf = (char *) xmalloc (len);
- char *buf2 = (char *) xmalloc (len);
- int i = 0;
+ int reg;
-#ifdef REGISTER_PREFIX
- buf[i++] = REGISTER_PREFIX;
-#endif
+ if ((reg = arm_reg_parse (strp)) == FAIL || ! int_register (reg))
+ {
+ inst.error = "Register expected";
+ return FAIL;
+ }
- strcpy (buf + i, reg_table[entry].name);
+ switch (hi_lo)
+ {
+ case THUMB_REG_LO:
+ if (reg > 7)
+ {
+ inst.error = "lo register required";
+ return FAIL;
+ }
+ break;
- for (i = 0; buf[i]; i++)
- buf2[i] = islower (buf[i]) ? toupper (buf[i]) : buf[i];
+ case THUMB_REG_HI:
+ if (reg < 8)
+ {
+ inst.error = "hi register required";
+ return FAIL;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return reg;
+}
+
+/* Parse an add or subtract instruction, SUBTRACT is non-zero if the opcode
+ was SUB. */
+static void
+thumb_add_sub (str, subtract)
+ char *str;
+ int subtract;
+{
+ int Rd, Rs, Rn = FAIL;
+
+ while (*str == ' ')
+ str++;
+
+ if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
+ || skip_past_comma (&str) == FAIL)
+ {
+ if (! inst.error)
+ inst.error = bad_args;
+ return;
+ }
+
+ if (*str == '#')
+ {
+ Rs = Rd;
+ str++;
+ if (my_get_expression (&inst.reloc.exp, &str))
+ return;
+ }
+ else
+ {
+ if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+ return;
+
+ if (skip_past_comma (&str) == FAIL)
+ {
+ /* Two operand format, shuffle the registers and pretend there
+ are 3 */
+ Rn = Rs;
+ Rs = Rd;
+ }
+ else if (*str == '#')
+ {
+ str++;
+ if (my_get_expression (&inst.reloc.exp, &str))
+ return;
+ }
+ else if ((Rn = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+ return;
+ }
+
+ /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
+ for the latter case, EXPR contains the immediate that was found. */
+ if (Rn != FAIL)
+ {
+ /* All register format. */
+ if (Rd > 7 || Rs > 7 || Rd > 7)
+ {
+ if (Rs != Rd)
+ {
+ inst.error = "dest and source1 must be the same register";
+ return;
+ }
+
+ /* Can't do this for SUB */
+ if (subtract)
+ {
+ inst.error = "subtract valid only on lo regs";
+ return;
+ }
+
+ inst.instruction = (T_OPCODE_ADD_HI
+ | (Rd > 7 ? THUMB_H1 : 0)
+ | (Rn > 7 ? THUMB_H2 : 0));
+ inst.instruction |= (Rd & 7) | ((Rn & 7) << 3);
+ }
+ else
+ {
+ inst.instruction = subtract ? T_OPCODE_SUB_R3 : T_OPCODE_ADD_R3;
+ inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
+ }
+ }
+ else
+ {
+ /* Immediate expression, now things start to get nasty. */
+
+ /* First deal with HI regs, only very restricted cases allowed:
+ Adjusting SP, and using PC or SP to get an address. */
+ if ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
+ || (Rs > 7 && Rs != REG_SP && Rs != REG_PC))
+ {
+ inst.error = "invalid Hi register with immediate";
+ return;
+ }
+
+ if (inst.reloc.exp.X_op != O_constant)
+ {
+ /* Value isn't known yet, all we can do is store all the fragments
+ we know about in the instruction and let the reloc hacking
+ work it all out. */
+ inst.instruction = (subtract ? 0x8000 : 0) | (Rd << 4) | Rs;
+ inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+ }
+ else
+ {
+ int offset = inst.reloc.exp.X_add_number;
+
+ if (subtract)
+ offset = -offset;
+
+ if (offset < 0)
+ {
+ offset = -offset;
+ subtract = 1;
+
+ /* Quick check, in case offset is MIN_INT */
+ if (offset < 0)
+ {
+ inst.error = "immediate value out of range";
+ return;
+ }
+ }
+ else
+ subtract = 0;
+
+ if (Rd == REG_SP)
+ {
+ if (offset & ~0x1fc)
+ {
+ inst.error = "invalid immediate value for stack adjust";
+ return;
+ }
+ inst.instruction = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
+ inst.instruction |= offset >> 2;
+ }
+ else if (Rs == REG_PC || Rs == REG_SP)
+ {
+ if (subtract
+ || (offset & ~0x3fc))
+ {
+ inst.error = "invalid immediate for address calculation";
+ return;
+ }
+ inst.instruction = (Rs == REG_PC ? T_OPCODE_ADD_PC
+ : T_OPCODE_ADD_SP);
+ inst.instruction |= (Rd << 8) | (offset >> 2);
+ }
+ else if (Rs == Rd)
+ {
+ if (offset & ~0xff)
+ {
+ inst.error = "immediate value out of range";
+ return;
+ }
+ inst.instruction = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
+ inst.instruction |= (Rd << 8) | offset;
+ }
+ else
+ {
+ if (offset & ~0x7)
+ {
+ inst.error = "immediate value out of range";
+ return;
+ }
+ inst.instruction = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
+ inst.instruction |= Rd | (Rs << 3) | (offset << 6);
+ }
+ }
+ }
+ end_of_line (str);
+}
+
+static void
+thumb_shift (str, shift)
+ char *str;
+ int shift;
+{
+ int Rd, Rs, Rn = FAIL;
+
+ while (*str == ' ')
+ str++;
+
+ if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+ || skip_past_comma (&str) == FAIL)
+ {
+ if (! inst.error)
+ inst.error = bad_args;
+ return;
+ }
+
+ if (*str == '#')
+ {
+ /* Two operand immediate format, set Rs to Rd. */
+ Rs = Rd;
+ str++;
+ if (my_get_expression (&inst.reloc.exp, &str))
+ return;
+ }
+ else
+ {
+ if ((Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+ return;
+
+ if (skip_past_comma (&str) == FAIL)
+ {
+ /* Two operand format, shuffle the registers and pretend there
+ are 3 */
+ Rn = Rs;
+ Rs = Rd;
+ }
+ else if (*str == '#')
+ {
+ str++;
+ if (my_get_expression (&inst.reloc.exp, &str))
+ return;
+ }
+ else if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+ return;
+ }
+
+ /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
+ for the latter case, EXPR contains the immediate that was found. */
+
+ if (Rn != FAIL)
+ {
+ if (Rs != Rd)
+ {
+ inst.error = "source1 and dest must be same register";
+ return;
+ }
+
+ switch (shift)
+ {
+ case THUMB_ASR: inst.instruction = T_OPCODE_ASR_R; break;
+ case THUMB_LSL: inst.instruction = T_OPCODE_LSL_R; break;
+ case THUMB_LSR: inst.instruction = T_OPCODE_LSR_R; break;
+ }
+
+ inst.instruction |= Rd | (Rn << 3);
+ }
+ else
+ {
+ switch (shift)
+ {
+ case THUMB_ASR: inst.instruction = T_OPCODE_ASR_I; break;
+ case THUMB_LSL: inst.instruction = T_OPCODE_LSL_I; break;
+ case THUMB_LSR: inst.instruction = T_OPCODE_LSR_I; break;
+ }
+
+ if (inst.reloc.exp.X_op != O_constant)
+ {
+ /* Value isn't known yet, create a dummy reloc and let reloc
+ hacking fix it up */
+
+ inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
+ }
+ else
+ {
+ unsigned shift_value = inst.reloc.exp.X_add_number;
+
+ if (shift_value > 32 || (shift_value == 32 && shift == THUMB_LSL))
+ {
+ inst.error = "Invalid immediate for shift";
+ return;
+ }
+
+ /* Shifts of zero are handled by converting to LSL */
+ if (shift_value == 0)
+ inst.instruction = T_OPCODE_LSL_I;
+
+ /* Shifts of 32 are encoded as a shift of zero */
+ if (shift_value == 32)
+ shift_value = 0;
+
+ inst.instruction |= shift_value << 6;
+ }
+
+ inst.instruction |= Rd | (Rs << 3);
+ }
+ end_of_line (str);
+}
+
+static void
+thumb_mov_compare (str, move)
+ char *str;
+ int move;
+{
+ int Rd, Rs = FAIL;
+
+ while (*str == ' ')
+ str++;
+
+ if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
+ || skip_past_comma (&str) == FAIL)
+ {
+ if (! inst.error)
+ inst.error = bad_args;
+ return;
+ }
+
+ if (*str == '#')
+ {
+ str++;
+ if (my_get_expression (&inst.reloc.exp, &str))
+ return;
+ }
+ else if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+ return;
+
+ if (Rs != FAIL)
+ {
+ if (Rs < 8 && Rd < 8)
+ {
+ if (move == THUMB_MOVE)
+ /* A move of two lowregs is, by convention, encoded as
+ ADD Rd, Rs, #0 */
+ inst.instruction = T_OPCODE_ADD_I3;
+ else
+ inst.instruction = T_OPCODE_CMP_LR;
+ inst.instruction |= Rd | (Rs << 3);
+ }
+ else
+ {
+ if (move == THUMB_MOVE)
+ inst.instruction = T_OPCODE_MOV_HR;
+ else
+ inst.instruction = T_OPCODE_CMP_HR;
+
+ if (Rd > 7)
+ inst.instruction |= THUMB_H1;
+
+ if (Rs > 7)
+ inst.instruction |= THUMB_H2;
+
+ inst.instruction |= (Rd & 7) | ((Rs & 7) << 3);
+ }
+ }
+ else
+ {
+ if (Rd > 7)
+ {
+ inst.error = "only lo regs allowed with immediate";
+ return;
+ }
+
+ if (move == THUMB_MOVE)
+ inst.instruction = T_OPCODE_MOV_I8;
+ else
+ inst.instruction = T_OPCODE_CMP_I8;
+
+ inst.instruction |= Rd << 8;
+
+ if (inst.reloc.exp.X_op != O_constant)
+ inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
+ else
+ {
+ unsigned value = inst.reloc.exp.X_add_number;
+
+ if (value > 255)
+ {
+ inst.error = "invalid immediate";
+ return;
+ }
+
+ inst.instruction |= value;
+ }
+ }
+
+ end_of_line (str);
+}
+
+static void
+thumb_load_store (str, load_store, size)
+ char *str;
+ int load_store;
+ int size;
+{
+ int Rd, Rb, Ro = FAIL;
+
+ while (*str == ' ')
+ str++;
+
+ if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+ || skip_past_comma (&str) == FAIL)
+ {
+ if (! inst.error)
+ inst.error = bad_args;
+ return;
+ }
+
+ if (*str == '[')
+ {
+ str++;
+ if ((Rb = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+ return;
+
+ if (skip_past_comma (&str) != FAIL)
+ {
+ if (*str == '#')
+ {
+ str++;
+ if (my_get_expression (&inst.reloc.exp, &str))
+ return;
+ }
+ else if ((Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+ return;
+ }
+ else
+ {
+ inst.reloc.exp.X_op = O_constant;
+ inst.reloc.exp.X_add_number = 0;
+ }
+
+ if (*str != ']')
+ {
+ inst.error = "expected ']'";
+ return;
+ }
+ str++;
+ }
+ else if (*str == '=')
+ {
+ abort ();
+ }
+ else
+ {
+ if (my_get_expression (&inst.reloc.exp, &str))
+ return;
+
+ inst.instruction = T_OPCODE_LDR_PC | (Rd << 8);
+ inst.reloc.pc_rel = 1;
+ inst.reloc.exp.X_add_number -= 4; /* Pipeline offset */
+ inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+ end_of_line (str);
+ return;
+ }
+
+ if (Rb == REG_PC || Rb == REG_SP)
+ {
+ if (size != THUMB_WORD)
+ {
+ inst.error = "byte or halfword not valid for base register";
+ return;
+ }
+ else if (Rb == REG_PC && load_store != THUMB_LOAD)
+ {
+ inst.error = "R15 based store not allowed";
+ return;
+ }
+ else if (Ro != FAIL)
+ {
+ inst.error = "Invalid base register for register offset";
+ return;
+ }
+
+ if (Rb == REG_PC)
+ inst.instruction = T_OPCODE_LDR_PC;
+ else if (load_store == THUMB_LOAD)
+ inst.instruction = T_OPCODE_LDR_SP;
+ else
+ inst.instruction = T_OPCODE_STR_SP;
+
+ inst.instruction |= Rd << 8;
+ if (inst.reloc.exp.X_op == O_constant)
+ {
+ unsigned offset = inst.reloc.exp.X_add_number;
+
+ if (offset & ~0x3fc)
+ {
+ inst.error = "invalid offset";
+ return;
+ }
+
+ inst.instruction |= offset >> 2;
+ }
+ else
+ inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+ }
+ else if (Rb > 7)
+ {
+ inst.error = "invalid base register in load/store";
+ return;
+ }
+ else if (Ro == FAIL)
+ {
+ /* Immediate offset */
+ if (size == THUMB_WORD)
+ inst.instruction = (load_store == THUMB_LOAD
+ ? T_OPCODE_LDR_IW : T_OPCODE_STR_IW);
+ else if (size == THUMB_HALFWORD)
+ inst.instruction = (load_store == THUMB_LOAD
+ ? T_OPCODE_LDR_IH : T_OPCODE_STR_IH);
+ else
+ inst.instruction = (load_store == THUMB_LOAD
+ ? T_OPCODE_LDR_IB : T_OPCODE_STR_IB);
+
+ inst.instruction |= Rd | (Rb << 3);
+
+ if (inst.reloc.exp.X_op == O_constant)
+ {
+ unsigned offset = inst.reloc.exp.X_add_number;
+
+ if (offset & ~(0x1f << size))
+ {
+ inst.error = "Invalid offset";
+ return;
+ }
+ inst.instruction |= offset << 6;
+ }
+ else
+ inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+ }
+ else
+ {
+ /* Register offset */
+ if (size == THUMB_WORD)
+ inst.instruction = (load_store == THUMB_LOAD
+ ? T_OPCODE_LDR_RW : T_OPCODE_STR_RW);
+ else if (size == THUMB_HALFWORD)
+ inst.instruction = (load_store == THUMB_LOAD
+ ? T_OPCODE_LDR_RH : T_OPCODE_STR_RH);
+ else
+ inst.instruction = (load_store == THUMB_LOAD
+ ? T_OPCODE_LDR_RB : T_OPCODE_STR_RB);
+
+ inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
+ }
+
+ end_of_line (str);
+}
+
+/* Handle the Format 4 instructions that do not have equivalents in other
+ formats. That is, ADC, AND, EOR, SBC, ROR, TST, NEG, CMN, ORR, MUL,
+ BIC and MVN. */
+static void
+do_t_arit (str)
+ char *str;
+{
+ int Rd, Rs, Rn;
+
+ while (*str == ' ')
+ str++;
+
+ if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+ return;
+
+ if (skip_past_comma (&str) == FAIL
+ || (Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+ {
+ if (! inst.error)
+ inst.error = bad_args;
+ return;
+ }
+
+ if (skip_past_comma (&str) != FAIL)
+ {
+ /* Three operand format not allowed for TST, CMN, NEG and MVN.
+ (It isn't allowed for CMP either, but that isn't handled by this
+ function.) */
+ if (inst.instruction == T_OPCODE_TST
+ || inst.instruction == T_OPCODE_CMN
+ || inst.instruction == T_OPCODE_NEG
+ || inst.instruction == T_OPCODE_MVN)
+ {
+ inst.error = bad_args;
+ return;
+ }
+
+ if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+ return;
+
+ if (Rs != Rd)
+ {
+ inst.error = "dest and source1 one must be the same register";
+ return;
+ }
+ Rs = Rn;
+ }
+
+ if (inst.instruction == T_OPCODE_MUL
+ && Rs == Rd)
+ as_tsktsk ("Rs and Rd must be different in MUL");
+
+ inst.instruction |= Rd | (Rs << 3);
+ end_of_line (str);
+}
+
+static void
+do_t_add (str)
+ char *str;
+{
+ thumb_add_sub (str, 0);
+}
+
+static void
+do_t_asr (str)
+ char *str;
+{
+ thumb_shift (str, THUMB_ASR);
+}
+
+static void
+do_t_branch (str)
+ char *str;
+{
+ if (my_get_expression (&inst.reloc.exp, &str))
+ return;
+ inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
+ inst.reloc.pc_rel = 1;
+ end_of_line (str);
+}
+
+static void
+do_t_bx (str)
+ char *str;
+{
+ int reg;
+
+ while (*str == ' ')
+ str++;
+
+ if ((reg = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+ return;
+
+ /* This sets THUMB_H2 from the top bit of reg. */
+ inst.instruction |= reg << 3;
+
+ /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC. The reloc
+ should cause the alignment to be checked once it is known. This is
+ because BX PC only works if the instruction is word aligned. */
+
+ end_of_line (str);
+}
+
+static void
+do_t_compare (str)
+ char *str;
+{
+ thumb_mov_compare (str, THUMB_COMPARE);
+}
+
+static void
+do_t_ldmstm (str)
+ char *str;
+{
+ int Rb;
+ long range;
+
+ while (*str == ' ')
+ str++;
+
+ if ((Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+ return;
+
+ if (*str != '!')
+ as_warn ("Inserted missing '!': load/store multiple always writes back base register");
+ else
+ str++;
+
+ if (skip_past_comma (&str) == FAIL
+ || (range = reg_list (&str)) == FAIL)
+ {
+ if (! inst.error)
+ inst.error = bad_args;
+ return;
+ }
+
+ if (inst.reloc.type != BFD_RELOC_NONE)
+ {
+ /* This really doesn't seem worth it. */
+ inst.reloc.type = BFD_RELOC_NONE;
+ inst.error = "Expression too complex";
+ return;
+ }
+
+ if (range & ~0xff)
+ {
+ inst.error = "only lo-regs valid in load/store multiple";
+ return;
+ }
+
+ inst.instruction |= (Rb << 8) | range;
+ end_of_line (str);
+}
+
+static void
+do_t_ldr (str)
+ char *str;
+{
+ thumb_load_store (str, THUMB_LOAD, THUMB_WORD);
+}
+
+static void
+do_t_ldrb (str)
+ char *str;
+{
+ thumb_load_store (str, THUMB_LOAD, THUMB_BYTE);
+}
+
+static void
+do_t_ldrh (str)
+ char *str;
+{
+ thumb_load_store (str, THUMB_LOAD, THUMB_HALFWORD);
+}
+
+static void
+do_t_lds (str)
+ char *str;
+{
+ int Rd, Rb, Ro;
+
+ while (*str == ' ')
+ str++;
+
+ if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+ || skip_past_comma (&str) == FAIL
+ || *str++ != '['
+ || (Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+ || skip_past_comma (&str) == FAIL
+ || (Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+ || *str++ != ']')
+ {
+ if (! inst.error)
+ inst.error = "Syntax: ldrs[b] Rd, [Rb, Ro]";
+ return;
+ }
+
+ inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
+ end_of_line (str);
+}
+
+static void
+do_t_lsl (str)
+ char *str;
+{
+ thumb_shift (str, THUMB_LSL);
+}
+
+static void
+do_t_lsr (str)
+ char *str;
+{
+ thumb_shift (str, THUMB_LSR);
+}
+
+static void
+do_t_mov (str)
+ char *str;
+{
+ thumb_mov_compare (str, THUMB_MOVE);
+}
+
+static void
+do_t_push_pop (str)
+ char *str;
+{
+ long range;
+
+ while (*str == ' ')
+ str++;
+
+ if ((range = reg_list (&str)) == FAIL)
+ {
+ if (! inst.error)
+ inst.error = bad_args;
+ return;
+ }
+
+ if (inst.reloc.type != BFD_RELOC_NONE)
+ {
+ /* This really doesn't seem worth it. */
+ inst.reloc.type = BFD_RELOC_NONE;
+ inst.error = "Expression too complex";
+ return;
+ }
+
+ if (range & ~0xff)
+ {
+ if ((inst.instruction == T_OPCODE_PUSH
+ && (range & ~0xff) == 1 << REG_LR)
+ || (inst.instruction == T_OPCODE_POP
+ && (range & ~0xff) == 1 << REG_PC))
+ {
+ inst.instruction |= THUMB_PP_PC_LR;
+ range &= 0xff;
+ }
+ else
+ {
+ inst.error = "invalid register list to push/pop instruction";
+ return;
+ }
+ }
+
+ inst.instruction |= range;
+ end_of_line (str);
+}
+
+static void
+do_t_str (str)
+ char *str;
+{
+ thumb_load_store (str, THUMB_STORE, THUMB_WORD);
+}
+
+static void
+do_t_strb (str)
+ char *str;
+{
+ thumb_load_store (str, THUMB_STORE, THUMB_BYTE);
+}
+
+static void
+do_t_strh (str)
+ char *str;
+{
+ thumb_load_store (str, THUMB_STORE, THUMB_HALFWORD);
+}
+
+static void
+do_t_sub (str)
+ char *str;
+{
+ thumb_add_sub (str, 1);
+}
+
+static void
+do_t_swi (str)
+ char *str;
+{
+ while (*str == ' ')
+ str++;
+
+ if (my_get_expression (&inst.reloc.exp, &str))
+ return;
+
+ inst.reloc.type = BFD_RELOC_ARM_SWI;
+ end_of_line (str);
+ return;
+}
+
+static void
+do_t_adr (str)
+ char *str;
+{
+ /* This is a pseudo-op of the form "adr rd, label" to be converted
+ into a relative address of the form "add rd, pc, #label-.-8" */
+ while (*str == ' ')
+ str++;
+
+ if (reg_required_here (&str, 8) == FAIL
+ || skip_past_comma (&str) == FAIL
+ || my_get_expression (&inst.reloc.exp, &str))
+ {
+ if (!inst.error)
+ inst.error = bad_args;
+ return;
+ }
+
+ inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+ inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */
+ inst.reloc.pc_rel = 1;
+ inst.instruction |= REG_PC; /* Rd is already placed into the instruction */
+ end_of_line (str);
+}
+
+static void
+insert_reg (entry)
+ int entry;
+{
+ int len = strlen (reg_table[entry].name) + 2;
+ char *buf = (char *) xmalloc (len);
+ char *buf2 = (char *) xmalloc (len);
+ int i = 0;
+
+#ifdef REGISTER_PREFIX
+ buf[i++] = REGISTER_PREFIX;
+#endif
+
+ strcpy (buf + i, reg_table[entry].name);
+
+ for (i = 0; buf[i]; i++)
+ buf2[i] = islower (buf[i]) ? toupper (buf[i]) : buf[i];
buf2[i] = '\0';
int i;
if ((arm_ops_hsh = hash_new ()) == NULL
+ || (arm_tops_hsh = hash_new ()) == NULL
|| (arm_cond_hsh = hash_new ()) == NULL
|| (arm_shift_hsh = hash_new ()) == NULL
|| (arm_reg_hsh = hash_new ()) == NULL
for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++)
hash_insert (arm_ops_hsh, insns[i].template, (PTR) (insns + i));
+ for (i = 0; i < sizeof (tinsns) / sizeof (struct thumb_opcode); i++)
+ hash_insert (arm_tops_hsh, tinsns[i].template, (PTR) (tinsns + i));
for (i = 0; i < sizeof (conds) / sizeof (struct asm_cond); i++)
hash_insert (arm_cond_hsh, conds[i].template, (PTR) (conds + i));
for (i = 0; i < sizeof (shift) / sizeof (struct asm_shift); i++)
offsetT newval, temp;
int sign;
char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+ arm_fix_data *arm_data = (arm_fix_data *) fixP->tc_fix_data;
assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
{
case BFD_RELOC_ARM_IMMEDIATE:
newval = validate_immediate (value);
- temp = md_chars_to_number (buf, insn_size);
+ temp = md_chars_to_number (buf, INSN_SIZE);
/* If the instruction will fail, see if we can fix things up by
changing the opcode. */
}
newval |= (temp & 0xfffff000);
- md_number_to_chars (buf, newval, insn_size);
+ md_number_to_chars (buf, newval, INSN_SIZE);
break;
case BFD_RELOC_ARM_OFFSET_IMM:
if (value < 0)
value = -value;
- newval = md_chars_to_number (buf, insn_size);
+ newval = md_chars_to_number (buf, INSN_SIZE);
newval &= 0xff7ff000;
- newval |= value | (sign ? 0x00800000 : 0);
- md_number_to_chars (buf, newval, insn_size);
+ newval |= value | (sign ? INDEX_UP : 0);
+ md_number_to_chars (buf, newval, INSN_SIZE);
break;
case BFD_RELOC_ARM_OFFSET_IMM8:
if (value < 0)
value = -value;
- newval = md_chars_to_number (buf, insn_size);
+ newval = md_chars_to_number (buf, INSN_SIZE);
newval &= 0xff7ff0f0;
- newval |= ((value >> 4) << 8) | value & 0xf | (sign ? 0x00800000 : 0);
- md_number_to_chars (buf, newval, insn_size);
+ newval |= ((value >> 4) << 8) | value & 0xf | (sign ? INDEX_UP : 0);
+ md_number_to_chars (buf, newval, INSN_SIZE);
break;
case BFD_RELOC_ARM_LITERAL:
break;
}
- newval = md_chars_to_number (buf, insn_size);
+ newval = md_chars_to_number (buf, INSN_SIZE);
newval &= 0xff7ff000;
- newval |= value | (sign ? 0x00800000 : 0);
- md_number_to_chars (buf, newval, insn_size);
+ newval |= value | (sign ? INDEX_UP : 0);
+ md_number_to_chars (buf, newval, INSN_SIZE);
break;
case BFD_RELOC_ARM_SHIFT_IMM:
- newval = md_chars_to_number (buf, insn_size);
+ newval = md_chars_to_number (buf, INSN_SIZE);
if (((unsigned long) value) > 32
|| (value == 32
&& (((newval & 0x60) == 0) || (newval & 0x60) == 0x60)))
value = 0;
newval &= 0xfffff07f;
newval |= (value & 0x1f) << 7;
- md_number_to_chars (buf, newval , insn_size);
+ md_number_to_chars (buf, newval , INSN_SIZE);
break;
case BFD_RELOC_ARM_SWI:
- if (((unsigned long) value) > 0x00ffffff)
- as_bad_where (fixP->fx_file, fixP->fx_line, "Invalid swi expression");
- newval = md_chars_to_number (buf, insn_size) & 0xff000000;
- newval |= value;
- md_number_to_chars (buf, newval , insn_size);
+ if (arm_data->thumb_mode)
+ {
+ if (((unsigned long) value) > 0xff)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Invalid swi expression");
+ newval = md_chars_to_number (buf, THUMB_SIZE) & 0xff00;
+ newval |= value;
+ md_number_to_chars (buf, newval, THUMB_SIZE);
+ }
+ else
+ {
+ if (((unsigned long) value) > 0x00ffffff)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Invalid swi expression");
+ newval = md_chars_to_number (buf, INSN_SIZE) & 0xff000000;
+ newval |= value;
+ md_number_to_chars (buf, newval , INSN_SIZE);
+ }
break;
case BFD_RELOC_ARM_MULTI:
if (((unsigned long) value) > 0xffff)
as_bad_where (fixP->fx_file, fixP->fx_line,
"Invalid expression in load/store multiple");
- newval = value | md_chars_to_number (buf, insn_size);
- md_number_to_chars (buf, newval, insn_size);
+ newval = value | md_chars_to_number (buf, INSN_SIZE);
+ md_number_to_chars (buf, newval, INSN_SIZE);
break;
case BFD_RELOC_ARM_PCREL_BRANCH:
- value = (value >> 2) & 0x00ffffff;
- newval = md_chars_to_number (buf, insn_size);
- value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
- newval = value | (newval & 0xff000000);
- md_number_to_chars (buf, newval, insn_size);
+ if (arm_data->thumb_mode)
+ {
+ unsigned long newval2;
+ newval = md_chars_to_number (buf, THUMB_SIZE);
+ if (fixP->fx_size == 4)
+ {
+ unsigned long diff;
+
+ newval2 = md_chars_to_number (buf, THUMB_SIZE);
+ diff = ((newval & 0x7ff) << 12) | ((newval2 & 0x7ff) << 1);
+ if (diff & 0x400000)
+ diff |= ~0x3fffff;
+ value += diff;
+ if ((value & 0x400000) && ((value & ~0x3fffff) != ~0x3fffff))
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Branch with link out of range");
+
+ newval = (newval & 0xf800) | ((value & 0x7fffff) >> 12);
+ newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
+ md_number_to_chars (buf, newval, THUMB_SIZE);
+ md_number_to_chars (buf, newval2, THUMB_SIZE);
+ }
+ else
+ {
+ if (newval == T_OPCODE_BRANCH)
+ {
+ unsigned long diff = (newval & 0x7ff) << 1;
+ if (diff & 0x800)
+ diff |= ~0x7ff;
+
+ value += diff;
+ if ((value & 0x800) && ((value & ~0x7ff) != ~0x7ff))
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Branch out of range");
+ newval = (newval & 0xf800) | ((value & 0xfff) >> 1);
+ }
+ else
+ {
+ unsigned long diff = (newval & 0xff) << 1;
+ if (diff & 0x100)
+ diff |= ~0xff;
+
+ value += diff;
+ if ((value & 0x100) && ((value & ~0xff) != ~0xff))
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Branch out of range");
+ newval = (newval & 0xff00) | ((value & 0x1ff) >> 1);
+ }
+ md_number_to_chars (buf, newval, THUMB_SIZE);
+ }
+ }
+ else
+ {
+ value = (value >> 2) & 0x00ffffff;
+ newval = md_chars_to_number (buf, INSN_SIZE);
+ value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
+ newval = value | (newval & 0xff000000);
+ md_number_to_chars (buf, newval, INSN_SIZE);
+ }
break;
case BFD_RELOC_8:
"Illegal value for co-processor offset");
if (value < 0)
value = -value;
- newval = md_chars_to_number (buf, insn_size) & 0xff7fff00;
- newval |= (value >> 2) | (sign ? 0x00800000 : 0);
- md_number_to_chars (buf, newval , insn_size);
+ newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00;
+ newval |= (value >> 2) | (sign ? INDEX_UP : 0);
+ md_number_to_chars (buf, newval , INSN_SIZE);
+ break;
+
+ case BFD_RELOC_ARM_THUMB_OFFSET:
+ newval = md_chars_to_number (buf, THUMB_SIZE);
+ /* Exactly what ranges, and where the offset is inserted depends on
+ the type of instruction, we can establish this from the top 4 bits */
+ switch (newval >> 12)
+ {
+ case 4: /* PC load */
+ /* PC loads are somewhat odd, bit 2 of the PC is forced to zero
+ for these loads, so we may need to round up the offset if the
+ instruction is not word aligned since the final address must
+ be. */
+
+ if ((fixP->fx_frag->fr_address + fixP->fx_where + value) & 3)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Invalid offset, target not word aligned");
+
+ if ((value + 2) & ~0x3fe)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Invalid offset");
+ /* Round up, since pc will be rounded down. */
+ newval |= (value + 2) >> 2;
+ break;
+
+ case 9: /* SP load/store */
+ if (value & ~0x3fc)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Invalid offset");
+ newval |= value >> 2;
+ break;
+
+ case 6: /* Word load/store */
+ if (value & ~0x7c)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Invalid offset");
+ newval |= value << 4; /* 6 - 2 */
+ break;
+
+ case 7: /* Byte load/store */
+ if (value & ~0x1f)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Invalid offset");
+ newval |= value << 6;
+ break;
+
+ case 8: /* Halfword load/store */
+ if (value & ~0x3e)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Invalid offset");
+ newval |= value << 5; /* 6 - 1 */
+ break;
+
+ default:
+ abort ();
+ }
+ md_number_to_chars (buf, newval, THUMB_SIZE);
+ break;
+
+ case BFD_RELOC_ARM_THUMB_ADD:
+ /* This is a complicated relocation, since we use it for all of
+ the following immediate relocations:
+ 3bit ADD/SUB
+ 8bit ADD/SUB
+ 9bit ADD/SUB SP word-aligned
+ 10bit ADD PC/SP word-aligned
+
+ The type of instruction being processed is encoded in the
+ instruction field:
+ 0x8000 SUB
+ 0x00F0 Rd
+ 0x000F Rs
+ */
+ newval = md_chars_to_number (buf, THUMB_SIZE);
+ {
+ int rd = (newval >> 4) & 0xf;
+ int rs = newval & 0xf;
+ int subtract = newval & 0x8000;
+
+ if (rd == REG_SP)
+ {
+ if (value & ~0x1fc)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Invalid immediate for stack address calculation");
+ newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
+ newval |= value >> 2;
+ }
+ else if (rs == REG_PC || rs == REG_SP)
+ {
+ if (subtract ||
+ value & ~0x3fc)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Invalid immediate for address calculation (value = 0x%08X)", value);
+ newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP);
+ newval |= value >> 2;
+ }
+ else if (rs == rd)
+ {
+ if (value & ~0xff)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Invalid 8bit immediate");
+ newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
+ newval |= (rd << 8) | value;
+ }
+ else
+ {
+ if (value & ~0x7)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Invalid 3bit immediate");
+ newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
+ newval |= rd | (rs << 3) | (value << 6);
+ }
+ }
+ md_number_to_chars (buf, newval , THUMB_SIZE);
+ break;
+
+ case BFD_RELOC_ARM_THUMB_IMM:
+ newval = md_chars_to_number (buf, THUMB_SIZE);
+ switch (newval >> 11)
+ {
+ case 0x04: /* 8bit immediate MOV */
+ case 0x05: /* 8bit immediate CMP */
+ if (value < 0 || value > 255)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Invalid immediate: %d is too large", value);
+ newval |= value;
+ break;
+
+ default:
+ abort ();
+ }
+ md_number_to_chars (buf, newval , THUMB_SIZE);
+ break;
+
+ case BFD_RELOC_ARM_THUMB_SHIFT:
+ /* 5bit shift value (0..31) */
+ if (value < 0 || value > 31)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "Illegal Thumb shift value: %d", value);
+ newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf03f;
+ newval |= value << 6;
+ md_number_to_chars (buf, newval , THUMB_SIZE);
break;
case BFD_RELOC_NONE:
arelent *reloc;
bfd_reloc_code_real_type code;
- reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
- assert (reloc != 0);
+ reloc = (arelent *) xmalloc (sizeof (arelent));
reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
, fixp->fx_r_type);
return NULL;
+ case BFD_RELOC_ARM_THUMB_OFFSET:
+ as_bad ("Internal_relocation (type %d) not fixed up (THUMB_OFFSET)"
+ , fixp->fx_r_type);
+ return NULL;
+
default:
abort ();
}
return;
}
- to = frag_more (insn_size);
- md_number_to_chars (to, inst.instruction, insn_size);
+ to = frag_more (inst.size);
+ if (thumb_mode && (inst.size > 2))
+ {
+ md_number_to_chars (to, inst.instruction >> 16, 2);
+ to += 2;
+ inst.size = 2;
+ }
+
+ md_number_to_chars (to, inst.instruction, inst.size);
if (inst.reloc.type != BFD_RELOC_NONE)
fix_new_arm (frag_now, to - frag_now->fr_literal,
- 4, &inst.reloc.exp, inst.reloc.pc_rel,
+ inst.size, &inst.reloc.exp, inst.reloc.pc_rel,
inst.reloc.type);
return;
char *str;
{
char c;
- CONST struct asm_opcode *opcode;
char *p, *q, *start;
/* Align the instruction */
return;
}
- /* p now points to the end of the opcode, probably white space, but we have
- to break the opcode up in case it contains condionals and flags;
- keep trying with progressively smaller basic instructions until one
- matches, or we run out of opcode. */
- q = (p - str > LONGEST_INST) ? str + LONGEST_INST : p;
- for (; q != str; q--)
+ if (thumb_mode)
{
- c = *q;
- *q = '\0';
- opcode = (CONST struct asm_opcode *) hash_find (arm_ops_hsh, str);
- *q = c;
- if (opcode && opcode->template)
- {
- unsigned long flag_bits = 0;
- char *r;
-
- /* Check that this instruction is supported for this CPU */
- if ((opcode->variants & cpu_variant) == 0)
- goto try_shorter;
+ CONST struct thumb_opcode *opcode;
+ c = *p;
+ *p = '\0';
+ opcode = (CONST struct thumb_opcode *) hash_find (arm_tops_hsh, str);
+ *p = c;
+ if (opcode)
+ {
inst.instruction = opcode->value;
- if (q == p) /* Just a simple opcode */
+ inst.size = opcode->size;
+ (*opcode->parms)(p);
+ output_inst (start);
+ return;
+ }
+ }
+ else
+ {
+ CONST struct asm_opcode *opcode;
+
+ inst.size = INSN_SIZE;
+ /* p now points to the end of the opcode, probably white space, but we
+ have to break the opcode up in case it contains condionals and flags;
+ keep trying with progressively smaller basic instructions until one
+ matches, or we run out of opcode. */
+ q = (p - str > LONGEST_INST) ? str + LONGEST_INST : p;
+ for (; q != str; q--)
+ {
+ c = *q;
+ *q = '\0';
+ opcode = (CONST struct asm_opcode *) hash_find (arm_ops_hsh, str);
+ *q = c;
+ if (opcode && opcode->template)
{
- if (opcode->comp_suffix != 0)
- as_bad ("Opcode `%s' must have suffix from <%s>\n", str,
- opcode->comp_suffix);
- else
+ unsigned long flag_bits = 0;
+ char *r;
+
+ /* Check that this instruction is supported for this CPU */
+ if ((opcode->variants & cpu_variant) == 0)
+ goto try_shorter;
+
+ inst.instruction = opcode->value;
+ if (q == p) /* Just a simple opcode */
{
- inst.instruction |= COND_ALWAYS;
- (*opcode->parms)(q, 0);
+ if (opcode->comp_suffix != 0)
+ as_bad ("Opcode `%s' must have suffix from <%s>\n", str,
+ opcode->comp_suffix);
+ else
+ {
+ inst.instruction |= COND_ALWAYS;
+ (*opcode->parms)(q, 0);
+ }
+ output_inst (start);
+ return;
}
- output_inst (start);
- return;
- }
- /* Now check for a conditional */
- r = q;
- if (p - r >= 2)
- {
- CONST struct asm_cond *cond;
- char d = *(r + 2);
-
- *(r + 2) = '\0';
- cond = (CONST struct asm_cond *) hash_find (arm_cond_hsh, r);
- *(r + 2) = d;
- if (cond)
+ /* Now check for a conditional */
+ r = q;
+ if (p - r >= 2)
{
- if (cond->value == 0xf0000000)
- as_tsktsk
- ("Warning: Use of the 'nv' conditional is deprecated\n");
+ CONST struct asm_cond *cond;
+ char d = *(r + 2);
+
+ *(r + 2) = '\0';
+ cond = (CONST struct asm_cond *) hash_find (arm_cond_hsh, r);
+ *(r + 2) = d;
+ if (cond)
+ {
+ if (cond->value == 0xf0000000)
+ as_tsktsk (
+"Warning: Use of the 'nv' conditional is deprecated\n");
- inst.instruction |= cond->value;
- r += 2;
+ inst.instruction |= cond->value;
+ r += 2;
+ }
+ else
+ inst.instruction |= COND_ALWAYS;
}
else
inst.instruction |= COND_ALWAYS;
- }
- else
- inst.instruction |= COND_ALWAYS;
-
- /* if there is a compulsory suffix, it should come here, before
- any optional flags. */
- if (opcode->comp_suffix)
- {
- CONST char *s = opcode->comp_suffix;
- while (*s)
- {
- inst.suffix++;
- if (*r == *s)
- break;
- s++;
- }
-
- if (*s == '\0')
+ /* if there is a compulsory suffix, it should come here, before
+ any optional flags. */
+ if (opcode->comp_suffix)
{
- as_bad ("Opcode `%s' must have suffix from <%s>\n", str,
- opcode->comp_suffix);
- return;
- }
-
- r++;
- }
+ CONST char *s = opcode->comp_suffix;
- /* The remainder, if any should now be flags for the instruction;
- Scan these checking each one found with the opcode. */
- if (r != p)
- {
- char d;
- CONST struct asm_flg *flag = opcode->flags;
+ while (*s)
+ {
+ inst.suffix++;
+ if (*r == *s)
+ break;
+ s++;
+ }
- if (flag)
- {
- int flagno;
+ if (*s == '\0')
+ {
+ as_bad ("Opcode `%s' must have suffix from <%s>\n", str,
+ opcode->comp_suffix);
+ return;
+ }
- d = *p;
- *p = '\0';
+ r++;
+ }
+
+ /* The remainder, if any should now be flags for the instruction;
+ Scan these checking each one found with the opcode. */
+ if (r != p)
+ {
+ char d;
+ CONST struct asm_flg *flag = opcode->flags;
- for (flagno = 0; flag[flagno].template; flagno++)
+ if (flag)
{
- if ((flag[flagno].variants & cpu_variant) != 0
- && (! strcmp (r, flag[flagno].template)))
+ int flagno;
+
+ d = *p;
+ *p = '\0';
+
+ for (flagno = 0; flag[flagno].template; flagno++)
{
- flag_bits |= flag[flagno].set_bits;
- break;
+ if (! strcmp (r, flag[flagno].template))
+ {
+ flag_bits |= flag[flagno].set_bits;
+ break;
+ }
}
- }
- *p = d;
- if (! flag[flagno].template)
+ *p = d;
+ if (! flag[flagno].template)
+ goto try_shorter;
+ }
+ else
goto try_shorter;
}
- else
- goto try_shorter;
+
+ (*opcode->parms) (p, flag_bits);
+ output_inst (start);
+ return;
}
- (*opcode->parms) (p, flag_bits);
- output_inst (start);
- return;
+ try_shorter:
+ ;
}
-
- try_shorter:
- ;
}
+
/* It wasn't an instruction, but it might be a register alias of the form
alias .req reg
*/
#endif
{NULL, no_argument, NULL, 0}
};
-size_t md_longopts_size = sizeof(md_longopts);
+size_t md_longopts_size = sizeof (md_longopts);
int
md_parse_option (c, arg)
cpu_variant &= ~FPU_ALL;
break;
+ case 't':
+ /* Limit assembler to generating only Thumb instructions: */
+ if (! strcmp (str, "thumb"))
+ {
+ cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB;
+ cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_NONE;
+ thumb_mode = 1;
+ }
+ else
+ goto bad;
+ break;
+
default:
if (! strcmp (str, "all"))
{
switch (*str)
{
case 't':
- cpu_variant |= ARM_HALFWORD;
+ cpu_variant |= ARM_THUMB;
break;
case 'm':
{
fprintf (fp,
"-m[arm]1, -m[arm]2, -m[arm]250,\n-m[arm]3, -m[arm]6, -m[arm]7[t][[d]m]\n\
-\t\t\tselect processor architecture\n\
+-mthumb\t\t\tselect processor architecture\n\
-mall\t\t\tallow any instruction\n\
-mfpa10, -mfpa11\tselect floating point architecture\n\
-mfpe-old\t\tdon't allow floating-point multiple instructions\n\
int reloc;
{
fixS *new_fix;
+ arm_fix_data *arm_data;
switch (exp->X_op)
{
break;
default:
- {
- const char *fake;
- symbolS *symbolP;
-
- /* FIXME: This should be something which decode_local_label_name
- will handle. */
- fake = FAKE_LABEL_NAME;
-
- /* Putting constant symbols in absolute_section rather than
- expr_section is convenient for the old a.out code, for which
- S_GET_SEGMENT does not always retrieve the value put in by
- S_SET_SEGMENT. */
- symbolP = symbol_new (fake, expr_section, 0, &zero_address_frag);
- symbolP->sy_value = *exp;
- new_fix = fix_new (frag, where, size, symbolP, 0, pc_rel, reloc);
- }
+ new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0,
+ pc_rel, reloc);
break;
}
+ /* Mark whether the fix is to a THUMB instruction, or an ARM instruction */
+ arm_data = (arm_fix_data *) obstack_alloc (¬es, sizeof (arm_fix_data));
+ new_fix->tc_fix_data = (PTR) arm_data;
+ arm_data->thumb_mode = thumb_mode;
+
return;
}
{
last_label_seen = sym;
}
+
+int
+arm_data_in_code ()
+{
+ if (thumb_mode && ! strncmp (input_line_pointer + 1, "data:", 5))
+ {
+ *input_line_pointer = '/';
+ input_line_pointer += 5;
+ *input_line_pointer = 0;
+ return 1;
+ }
+ return 0;
+}
+
+char *
+arm_canonicalize_symbol_name (name)
+ char *name;
+{
+ int len;
+
+ if (thumb_mode && (len = strlen (name)) > 5
+ && ! strcmp (name + len - 5, "/data"))
+ {
+ *(name + len - 5) = 0;
+ }
+
+ return name;
+}
/* Opcode hash table. */
static struct hash_control *d10v_hash;
-/* reg_name_search does a binary search of the pre_defined_registers
+/* reg_name_search does a binary search of the d10v_predefined_registers
array to see if "name" is a valid regiter name. Returns the register
number from the array on success, or -1 on failure. */
int cmp;
low = 0;
- high = reg_name_cnt() - 1;
+ high = d10v_reg_name_cnt() - 1;
do
{
middle = (low + high) / 2;
- cmp = strcasecmp (name, pre_defined_registers[middle].name);
+ cmp = strcasecmp (name, d10v_predefined_registers[middle].name);
if (cmp < 0)
high = middle - 1;
else if (cmp > 0)
low = middle + 1;
else
- return pre_defined_registers[middle].value;
+ return d10v_predefined_registers[middle].value;
}
while (low <= high);
return -1;
fixS *fixp;
{
arelent *reloc;
- reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
+ reloc = (arelent *) xmalloc (sizeof (arelent));
reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
/* This array holds the chars that always start a comment. If the
pre-processor is disabled, these aren't very useful */
-#if defined (TE_I386AIX) || defined (OBJ_ELF)
+#if defined (TE_I386AIX) || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
const char comment_chars[] = "#/";
#else
const char comment_chars[] = "#";
#NO_APP at the beginning of its output. */
/* Also note that comments started like this one will always work if
'/' isn't otherwise defined. */
-#if defined (TE_I386AIX) || defined (OBJ_ELF)
+#if defined (TE_I386AIX) || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
const char line_comment_chars[] = "";
#else
const char line_comment_chars[] = "/";
operand_chars[(unsigned char) *p] = *p;
}
-#ifdef OBJ_ELF
- record_alignment (text_section, 2);
- record_alignment (data_section, 2);
- record_alignment (bss_section, 2);
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+ {
+ record_alignment (text_section, 2);
+ record_alignment (data_section, 2);
+ record_alignment (bss_section, 2);
+ }
#endif
}
if (fixP->fx_r_type == BFD_RELOC_32_PCREL && fixP->fx_addsy)
{
#ifndef OBJ_AOUT
- value += fixP->fx_where + fixP->fx_frag->fr_address;
+ if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+ value += fixP->fx_where + fixP->fx_frag->fr_address;
#endif
-#ifdef OBJ_ELF
- if (S_GET_SEGMENT (fixP->fx_addsy) == seg
- || (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0)
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ if (OUTPUT_FLAVOR == bfd_target_elf_flavour
+ && (S_GET_SEGMENT (fixP->fx_addsy) == seg
+ || (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0))
{
/* Yes, we add the values in twice. This is because
bfd_perform_relocation subtracts them out again. I think
/* Fix a few things - the dynamic linker expects certain values here,
and we must not dissappoint it. */
-#ifdef OBJ_ELF
- if (fixP->fx_addsy)
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ if (OUTPUT_FLAVOR == bfd_target_elf_flavour
+ && fixP->fx_addsy)
switch(fixP->fx_r_type) {
case BFD_RELOC_386_PLT32:
/* Make the jump instruction point to the address of the operand. At
flag_do_long_jump = 1;
break;
-#ifdef OBJ_ELF
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
/* -k: Ignore for FreeBSD compatibility. */
case 'k':
break;
fprintf (stream, "\
-m do long jump\n");
}
-\f
-/* We have no need to default values of symbols. */
+#ifdef BFD_ASSEMBLER
+#ifdef OBJ_MAYBE_ELF
+#ifdef OBJ_MAYBE_COFF
+
+/* Pick the target format to use. */
+
+const char *
+i386_target_format ()
+{
+ switch (OUTPUT_FLAVOR)
+ {
+ case bfd_target_coff_flavour:
+ return "coff-i386";
+ case bfd_target_elf_flavour:
+ return "elf32-i386";
+ default:
+ abort ();
+ return NULL;
+ }
+}
+
+#endif /* OBJ_MAYBE_COFF */
+#endif /* OBJ_MAYBE_ELF */
+#endif /* BFD_ASSEMBLER */
+\f
/* ARGSUSED */
symbolS *
md_undefined_symbol (name)
&& fixp->fx_addsy == GOT_symbol)
code = BFD_RELOC_386_GOTPC;
- rel = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
- if (rel == NULL)
- as_fatal ("Out of memory");
+ rel = (arelent *) xmalloc (sizeof (arelent));
rel->sym_ptr_ptr = &fixp->fx_addsy->bsym;
rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
if (fixp->fx_pcrel)
first line of the input file. This is because the compiler outputs
#NO_APP at the beginning of its output. */
/* Also note that comments like this one will always work. */
-const char line_comment_chars[] = "#";
+const char line_comment_chars[] = "#*";
const char line_separator_chars[] = "";
#undef F
#undef MAP
- reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
- assert (reloc != 0);
+ reloc = (arelent *) xmalloc (sizeof (arelent));
reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
#ifndef OBJ_ELF
char c;
int losing;
int opsfound;
- char *crack_operand ();
LITTLENUM_TYPE words[6];
LITTLENUM_TYPE *wordp;
unsigned long ok_arch = 0;
n = 1;
break;
case 'w':
+ case 'W':
n = 2;
break;
case 'l':
/* tc-mn10300.c -- Assembler code for the Matsushita 10300
- Copyright (C) 1996 Free Software Foundation.
+ Copyright (C) 1996, 1997 Free Software Foundation.
This file is part of GAS, the GNU Assembler.
const char FLT_CHARS[] = "dD";
\f
+const relax_typeS md_relax_table[] = {
+ /* bCC relaxing */
+ {0x7f, -0x80, 2, 1},
+ {0x7fff, -0x8000, 5, 2},
+ {0x7fffffff, -0x80000000, 7, 0},
+
+ /* bCC relaxing (uncommon cases) */
+ {0x7f, -0x80, 3, 4},
+ {0x7fff, -0x8000, 6, 5},
+ {0x7fffffff, -0x80000000, 8, 0},
+
+ /* call relaxing */
+ {0x7fff, -0x8000, 5, 7},
+ {0x7fffffff, -0x80000000, 7, 0},
+
+ /* calls relaxing */
+ {0x7fff, -0x8000, 4, 9},
+ {0x7fffffff, -0x80000000, 6, 0},
+
+ /* jmp relaxing */
+ {0x7f, -0x80, 2, 11},
+ {0x7fff, -0x8000, 3, 12},
+ {0x7fffffff, -0x80000000, 5, 0},
+
+};
+
/* local functions */
static void mn10300_insert_operand PARAMS ((unsigned long *, unsigned long *,
const struct mn10300_operand *,
asection *sec;
fragS *fragP;
{
- /* printf ("call to md_convert_frag \n"); */
- abort ();
+ static unsigned long label_count = 0;
+ char buf[40];
+
+ subseg_change (sec, 0);
+ if (fragP->fr_subtype == 0)
+ {
+ fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
+ fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 2;
+ }
+ else if (fragP->fr_subtype == 1)
+ {
+ /* Reverse the condition of the first branch. */
+ int offset = fragP->fr_fix;
+ int opcode = fragP->fr_literal[offset] & 0xff;
+
+ switch (opcode)
+ {
+ case 0xc8:
+ opcode = 0xc9;
+ break;
+ case 0xc9:
+ opcode = 0xc8;
+ break;
+ case 0xc0:
+ opcode = 0xc2;
+ break;
+ case 0xc2:
+ opcode = 0xc0;
+ break;
+ case 0xc3:
+ opcode = 0xc1;
+ break;
+ case 0xc1:
+ opcode = 0xc3;
+ break;
+ case 0xc4:
+ opcode = 0xc6;
+ break;
+ case 0xc6:
+ opcode = 0xc4;
+ break;
+ case 0xc7:
+ opcode = 0xc5;
+ break;
+ case 0xc5:
+ opcode = 0xc7;
+ break;
+ default:
+ abort ();
+ }
+ fragP->fr_literal[offset] = opcode;
+
+ /* Create a fixup for the reversed conditional branch. */
+ sprintf (buf, "%s_%d", FAKE_LABEL_NAME, label_count++);
+ fix_new (fragP, fragP->fr_fix + 1, 1,
+ symbol_new (buf, sec, 0, fragP->fr_next),
+ fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
+
+ /* Now create the unconditional branch + fixup to the
+ final target. */
+ fragP->fr_literal[offset + 2] = 0xcc;
+ fix_new (fragP, fragP->fr_fix + 3, 2, fragP->fr_symbol,
+ fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 5;
+ }
+ else if (fragP->fr_subtype == 2)
+ {
+ /* Reverse the condition of the first branch. */
+ int offset = fragP->fr_fix;
+ int opcode = fragP->fr_literal[offset] & 0xff;
+
+ switch (opcode)
+ {
+ case 0xc8:
+ opcode = 0xc9;
+ break;
+ case 0xc9:
+ opcode = 0xc8;
+ break;
+ case 0xc0:
+ opcode = 0xc2;
+ break;
+ case 0xc2:
+ opcode = 0xc0;
+ break;
+ case 0xc3:
+ opcode = 0xc1;
+ break;
+ case 0xc1:
+ opcode = 0xc3;
+ break;
+ case 0xc4:
+ opcode = 0xc6;
+ break;
+ case 0xc6:
+ opcode = 0xc4;
+ break;
+ case 0xc7:
+ opcode = 0xc5;
+ break;
+ case 0xc5:
+ opcode = 0xc7;
+ break;
+ default:
+ abort ();
+ }
+ fragP->fr_literal[offset] = opcode;
+
+ /* Create a fixup for the reversed conditional branch. */
+ sprintf (buf, "%s_%d", FAKE_LABEL_NAME, label_count++);
+ fix_new (fragP, fragP->fr_fix + 1, 1,
+ symbol_new (buf, sec, 0, fragP->fr_next),
+ fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
+
+ /* Now create the unconditional branch + fixup to the
+ final target. */
+ fragP->fr_literal[offset + 2] = 0xdc;
+ fix_new (fragP, fragP->fr_fix + 3, 4, fragP->fr_symbol,
+ fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 7;
+ }
+ else if (fragP->fr_subtype == 3)
+ {
+ fix_new (fragP, fragP->fr_fix + 2, 1, fragP->fr_symbol,
+ fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 3;
+ }
+ else if (fragP->fr_subtype == 4)
+ {
+ /* Reverse the condition of the first branch. */
+ int offset = fragP->fr_fix;
+ int opcode = fragP->fr_literal[offset + 1] & 0xff;
+
+ switch (opcode)
+ {
+ case 0xe8:
+ opcode = 0xe9;
+ break;
+ case 0xe9:
+ opcode = 0xe8;
+ break;
+ case 0xea:
+ opcode = 0xeb;
+ break;
+ case 0xeb:
+ opcode = 0xea;
+ break;
+ default:
+ abort ();
+ }
+ fragP->fr_literal[offset + 1] = opcode;
+
+ /* Create a fixup for the reversed conditional branch. */
+ sprintf (buf, "%s_%d", FAKE_LABEL_NAME, label_count++);
+ fix_new (fragP, fragP->fr_fix + 2, 1,
+ symbol_new (buf, sec, 0, fragP->fr_next),
+ fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+
+ /* Now create the unconditional branch + fixup to the
+ final target. */
+ fragP->fr_literal[offset + 3] = 0xcc;
+ fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol,
+ fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 6;
+ }
+ else if (fragP->fr_subtype == 5)
+ {
+ /* Reverse the condition of the first branch. */
+ int offset = fragP->fr_fix;
+ int opcode = fragP->fr_literal[offset + 1] & 0xff;
+
+ switch (opcode)
+ {
+ case 0xe8:
+ opcode = 0xe9;
+ break;
+ case 0xea:
+ opcode = 0xeb;
+ break;
+ case 0xeb:
+ opcode = 0xea;
+ break;
+ default:
+ abort ();
+ }
+ fragP->fr_literal[offset + 1] = opcode;
+
+ /* Create a fixup for the reversed conditional branch. */
+ sprintf (buf, "%s_%d", FAKE_LABEL_NAME, label_count++);
+ fix_new (fragP, fragP->fr_fix + 2, 1,
+ symbol_new (buf, sec, 0, fragP->fr_next),
+ fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+
+ /* Now create the unconditional branch + fixup to the
+ final target. */
+ fragP->fr_literal[offset + 3] = 0xdc;
+ fix_new (fragP, fragP->fr_fix + 4, 4, fragP->fr_symbol,
+ fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 8;
+ }
+ else if (fragP->fr_subtype == 6)
+ {
+ int offset = fragP->fr_fix;
+ fragP->fr_literal[offset] = 0xcd;
+ fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
+ fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 5;
+ }
+ else if (fragP->fr_subtype == 7)
+ {
+ int offset = fragP->fr_fix;
+ fragP->fr_literal[offset] = 0xdd;
+ fragP->fr_literal[offset + 5] = fragP->fr_literal[offset + 3];
+ fragP->fr_literal[offset + 6] = fragP->fr_literal[offset + 4];
+
+ fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
+ fragP->fr_offset + 2, 1, BFD_RELOC_32_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 7;
+ }
+ else if (fragP->fr_subtype == 8)
+ {
+ int offset = fragP->fr_fix;
+ fragP->fr_literal[offset] = 0xfa;
+ fragP->fr_literal[offset + 1] = 0xff;
+ fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol,
+ fragP->fr_offset + 2, 1, BFD_RELOC_16_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 4;
+ }
+ else if (fragP->fr_subtype == 9)
+ {
+ int offset = fragP->fr_fix;
+ fragP->fr_literal[offset] = 0xfc;
+ fragP->fr_literal[offset + 1] = 0xff;
+
+ fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
+ fragP->fr_offset + 2, 1, BFD_RELOC_32_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 6;
+ }
+ else if (fragP->fr_subtype == 10)
+ {
+ fragP->fr_literal[fragP->fr_fix] = 0xca;
+ fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
+ fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 2;
+ }
+ else if (fragP->fr_subtype == 11)
+ {
+ int offset = fragP->fr_fix;
+ fragP->fr_literal[offset] = 0xcc;
+
+ fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
+ fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 3;
+ }
+ else if (fragP->fr_subtype == 12)
+ {
+ int offset = fragP->fr_fix;
+ fragP->fr_literal[offset] = 0xdc;
+
+ fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
+ fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 5;
+ }
+ else
+ abort ();
}
valueT
struct mn10300_opcode *opcode;
struct mn10300_opcode *next_opcode;
const unsigned char *opindex_ptr;
- int next_opindex;
+ int next_opindex, relaxable;
unsigned long insn, extension, size = 0;
char *f;
int i;
char *hold;
int extra_shift = 0;
+ relaxable = 0;
fc = 0;
match = 0;
next_opindex = 0;
while (*str == ' ' || *str == ',')
++str;
+ if (operand->flags & MN10300_OPERAND_RELAX)
+ relaxable = 1;
+
/* Gather the operand. */
hold = input_line_pointer;
input_line_pointer = str;
/* If this operand can be promoted, and it doesn't
fit into the allocated bitfield for this insn,
then promote it (ie this opcode does not match). */
- if (operand->flags & MN10300_OPERAND_PROMOTE
+ if (operand->flags
+ & (MN10300_OPERAND_PROMOTE | MN10300_OPERAND_RELAX)
&& ! check_operand (insn, operand, ex.X_add_number))
{
input_line_pointer = hold;
if (opcode->format == FMT_D4)
size = 6;
- /* Allocate space for the instruction. */
- f = frag_more (size);
-
- /* Fill in bytes for the instruction. Note that opcode fields
- are written big-endian, 16 & 32bit immediates are written
- little endian. Egad. */
- if (opcode->format == FMT_S0
- || opcode->format == FMT_S1
- || opcode->format == FMT_D0
- || opcode->format == FMT_D1)
- {
- number_to_chars_bigendian (f, insn, size);
- }
- else if (opcode->format == FMT_S2
- && opcode->opcode != 0xdf0000
- && opcode->opcode != 0xde0000)
- {
- /* A format S2 instruction that is _not_ "ret" and "retf". */
- number_to_chars_bigendian (f, (insn >> 16) & 0xff, 1);
- number_to_chars_littleendian (f + 1, insn & 0xffff, 2);
- }
- else if (opcode->format == FMT_S2)
- {
- /* This must be a ret or retf, which is written entirely in big-endian
- format. */
- number_to_chars_bigendian (f, insn, 3);
- }
- else if (opcode->format == FMT_S4
- && opcode->opcode != 0xdc000000)
- {
- /* This must be a format S4 "call" instruction. What a pain. */
- unsigned long temp = (insn >> 8) & 0xffff;
- number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
- number_to_chars_littleendian (f + 1, temp, 2);
- number_to_chars_bigendian (f + 3, insn & 0xff, 1);
- number_to_chars_bigendian (f + 4, extension & 0xff, 1);
- }
- else if (opcode->format == FMT_S4)
- {
- /* This must be a format S4 "jmp" instruction. */
- unsigned long temp = ((insn & 0xffffff) << 8) | (extension & 0xff);
- number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
- number_to_chars_littleendian (f + 1, temp, 4);
- }
- else if (opcode->format == FMT_S6)
- {
- unsigned long temp = ((insn & 0xffffff) << 8)
- | ((extension >> 16) & 0xff);
- number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
- number_to_chars_littleendian (f + 1, temp, 4);
- number_to_chars_bigendian (f + 5, (extension >> 8) & 0xff, 1);
- number_to_chars_bigendian (f + 6, extension & 0xff, 1);
- }
- else if (opcode->format == FMT_D2
- && opcode->opcode != 0xfaf80000
- && opcode->opcode != 0xfaf00000
- && opcode->opcode != 0xfaf40000)
- {
- /* A format D2 instruction where the 16bit immediate is
- really a single 16bit value, not two 8bit values. */
- number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
- number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
- }
- else if (opcode->format == FMT_D2)
- {
- /* A format D2 instruction where the 16bit immediate
- is really two 8bit immediates. */
- number_to_chars_bigendian (f, insn, 4);
- }
- else if (opcode->format == FMT_D4)
- {
- unsigned long temp = ((insn & 0xffff) << 16) | (extension & 0xffff);
- number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
- number_to_chars_littleendian (f + 2, temp, 4);
- }
- else if (opcode->format == FMT_D5)
+ if (relaxable && fc > 0)
{
- unsigned long temp = ((insn & 0xffff) << 16) | ((extension >> 8) & 0xffff);
- number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
- number_to_chars_littleendian (f + 2, temp, 4);
- number_to_chars_bigendian (f + 6, extension & 0xff, 1);
- }
+ int type;
+
+ /* bCC */
+ if (size == 2)
+ type = 0;
+ /* call */
+ else if (size == 5)
+ type = 6;
+ /* calls */
+ else if (size == 4)
+ type = 8;
+ /* jmp */
+ else if (size == 3 && opcode->opcode == 0xcc0000)
+ type = 10;
+ /* bCC (uncommon cases) */
+ else
+ type = 3;
- /* Create any fixups. */
- for (i = 0; i < fc; i++)
+ f = frag_var (rs_machine_dependent, 8, 8 - size, type,
+ fixups[0].exp.X_add_symbol,
+ fixups[0].exp.X_add_number,
+ (char *)fixups[0].opindex);
+
+ /* This is pretty hokey. We basically just care about the
+ opcode, so we have to write out the first word big endian.
+
+ The exception is "call", which has two operands that we
+ care about.
+
+ The first operand (the register list) happens to be in the
+ first instruction word, and will be in the right place if
+ we output the first word in big endian mode.
+
+ The second operand (stack size) is in the extension word,
+ and we want it to appear as the first character in the extension
+ word (as it appears in memory). Luckily, writing the extension
+ word in big endian format will do what we want. */
+ number_to_chars_bigendian (f, insn, size > 4 ? 4 : size);
+ if (size > 8)
+ {
+ number_to_chars_bigendian (f + 4, extension, 4);
+ number_to_chars_bigendian (f + 8, 0, size - 8);
+ }
+ else if (size > 4)
+ number_to_chars_bigendian (f + 4, extension, size - 4);
+ }
+ else
{
- const struct mn10300_operand *operand;
+ /* Allocate space for the instruction. */
+ f = frag_more (size);
+
+ /* Fill in bytes for the instruction. Note that opcode fields
+ are written big-endian, 16 & 32bit immediates are written
+ little endian. Egad. */
+ if (opcode->format == FMT_S0
+ || opcode->format == FMT_S1
+ || opcode->format == FMT_D0
+ || opcode->format == FMT_D1)
+ {
+ number_to_chars_bigendian (f, insn, size);
+ }
+ else if (opcode->format == FMT_S2
+ && opcode->opcode != 0xdf0000
+ && opcode->opcode != 0xde0000)
+ {
+ /* A format S2 instruction that is _not_ "ret" and "retf". */
+ number_to_chars_bigendian (f, (insn >> 16) & 0xff, 1);
+ number_to_chars_littleendian (f + 1, insn & 0xffff, 2);
+ }
+ else if (opcode->format == FMT_S2)
+ {
+ /* This must be a ret or retf, which is written entirely in
+ big-endian format. */
+ number_to_chars_bigendian (f, insn, 3);
+ }
+ else if (opcode->format == FMT_S4
+ && opcode->opcode != 0xdc000000)
+ {
+ /* This must be a format S4 "call" instruction. What a pain. */
+ unsigned long temp = (insn >> 8) & 0xffff;
+ number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
+ number_to_chars_littleendian (f + 1, temp, 2);
+ number_to_chars_bigendian (f + 3, insn & 0xff, 1);
+ number_to_chars_bigendian (f + 4, extension & 0xff, 1);
+ }
+ else if (opcode->format == FMT_S4)
+ {
+ /* This must be a format S4 "jmp" instruction. */
+ unsigned long temp = ((insn & 0xffffff) << 8) | (extension & 0xff);
+ number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
+ number_to_chars_littleendian (f + 1, temp, 4);
+ }
+ else if (opcode->format == FMT_S6)
+ {
+ unsigned long temp = ((insn & 0xffffff) << 8)
+ | ((extension >> 16) & 0xff);
+ number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
+ number_to_chars_littleendian (f + 1, temp, 4);
+ number_to_chars_bigendian (f + 5, (extension >> 8) & 0xff, 1);
+ number_to_chars_bigendian (f + 6, extension & 0xff, 1);
+ }
+ else if (opcode->format == FMT_D2
+ && opcode->opcode != 0xfaf80000
+ && opcode->opcode != 0xfaf00000
+ && opcode->opcode != 0xfaf40000)
+ {
+ /* A format D2 instruction where the 16bit immediate is
+ really a single 16bit value, not two 8bit values. */
+ number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
+ number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
+ }
+ else if (opcode->format == FMT_D2)
+ {
+ /* A format D2 instruction where the 16bit immediate
+ is really two 8bit immediates. */
+ number_to_chars_bigendian (f, insn, 4);
+ }
+ else if (opcode->format == FMT_D4)
+ {
+ unsigned long temp = ((insn & 0xffff) << 16) | (extension & 0xffff);
+ number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
+ number_to_chars_littleendian (f + 2, temp, 4);
+ }
+ else if (opcode->format == FMT_D5)
+ {
+ unsigned long temp = ((insn & 0xffff) << 16)
+ | ((extension >> 8) & 0xffff);
+ number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
+ number_to_chars_littleendian (f + 2, temp, 4);
+ number_to_chars_bigendian (f + 6, extension & 0xff, 1);
+ }
- operand = &mn10300_operands[fixups[i].opindex];
- if (fixups[i].reloc != BFD_RELOC_UNUSED)
+ /* Create any fixups. */
+ for (i = 0; i < fc; i++)
{
- reloc_howto_type *reloc_howto;
- int size;
- int offset;
- fixS *fixP;
+ const struct mn10300_operand *operand;
+
+ operand = &mn10300_operands[fixups[i].opindex];
+ if (fixups[i].reloc != BFD_RELOC_UNUSED)
+ {
+ reloc_howto_type *reloc_howto;
+ int size;
+ int offset;
+ fixS *fixP;
- reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
+ reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
- if (!reloc_howto)
- abort();
+ if (!reloc_howto)
+ abort();
- size = bfd_get_reloc_size (reloc_howto);
+ size = bfd_get_reloc_size (reloc_howto);
- if (size < 1 || size > 4)
- abort();
+ if (size < 1 || size > 4)
+ abort();
- offset = 4 - size;
- fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, size,
- &fixups[i].exp,
- reloc_howto->pc_relative,
- fixups[i].reloc);
- }
- else
- {
- int reloc, pcrel, reloc_size, offset;
- fixS *fixP;
-
- reloc = BFD_RELOC_NONE;
- /* How big is the reloc? Remember SPLIT relocs are
- implicitly 32bits. */
- if ((operand->flags & MN10300_OPERAND_SPLIT) != 0)
- reloc_size = 32;
+ offset = 4 - size;
+ fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
+ size, &fixups[i].exp,
+ reloc_howto->pc_relative,
+ fixups[i].reloc);
+ }
else
- reloc_size = operand->bits;
-
- /* Is the reloc pc-relative? */
- pcrel = (operand->flags & MN10300_OPERAND_PCREL) != 0;
-
- /* Gross. This disgusting hack is to make sure we
- get the right offset for the 16/32 bit reloc in
- "call" instructions. Basically they're a pain
- because the reloc isn't at the end of the instruction. */
- if ((size == 5 || size == 7)
- && (((insn >> 24) & 0xff) == 0xcd
- || ((insn >> 24) & 0xff) == 0xdd))
- size -= 2;
-
- /* Similarly for certain bit instructions which don't
- hav their 32bit reloc at the tail of the instruction. */
- if (size == 7
- && (((insn >> 16) & 0xffff) == 0xfe00
- || ((insn >> 16) & 0xffff) == 0xfe01
- || ((insn >> 16) & 0xffff) == 0xfe02))
- size -= 1;
+ {
+ int reloc, pcrel, reloc_size, offset;
+ fixS *fixP;
+
+ reloc = BFD_RELOC_NONE;
+ /* How big is the reloc? Remember SPLIT relocs are
+ implicitly 32bits. */
+ if ((operand->flags & MN10300_OPERAND_SPLIT) != 0)
+ reloc_size = 32;
+ else
+ reloc_size = operand->bits;
+
+ /* Is the reloc pc-relative? */
+ pcrel = (operand->flags & MN10300_OPERAND_PCREL) != 0;
+
+ /* Gross. This disgusting hack is to make sure we
+ get the right offset for the 16/32 bit reloc in
+ "call" instructions. Basically they're a pain
+ because the reloc isn't at the end of the instruction. */
+ if ((size == 5 || size == 7)
+ && (((insn >> 24) & 0xff) == 0xcd
+ || ((insn >> 24) & 0xff) == 0xdd))
+ size -= 2;
+
+ /* Similarly for certain bit instructions which don't
+ hav their 32bit reloc at the tail of the instruction. */
+ if (size == 7
+ && (((insn >> 16) & 0xffff) == 0xfe00
+ || ((insn >> 16) & 0xffff) == 0xfe01
+ || ((insn >> 16) & 0xffff) == 0xfe02))
+ size -= 1;
- offset = size - reloc_size / 8;
+ offset = size - reloc_size / 8;
- /* Choose a proper BFD relocation type. */
- if (pcrel)
- {
- if (reloc_size == 32)
- reloc = BFD_RELOC_32_PCREL;
- else if (reloc_size == 16)
- reloc = BFD_RELOC_16_PCREL;
- else if (reloc_size == 8)
- reloc = BFD_RELOC_8_PCREL;
+ /* Choose a proper BFD relocation type. */
+ if (pcrel)
+ {
+ if (reloc_size == 32)
+ reloc = BFD_RELOC_32_PCREL;
+ else if (reloc_size == 16)
+ reloc = BFD_RELOC_16_PCREL;
+ else if (reloc_size == 8)
+ reloc = BFD_RELOC_8_PCREL;
+ else
+ abort ();
+ }
else
- abort ();
- }
- else
- {
- if (reloc_size == 32)
- reloc = BFD_RELOC_32;
+ {
+ if (reloc_size == 32)
+ reloc = BFD_RELOC_32;
+ else if (reloc_size == 16)
+ reloc = BFD_RELOC_16;
+ else if (reloc_size == 8)
+ reloc = BFD_RELOC_8;
+ else
+ abort ();
+ }
+
+ /* Convert the size of the reloc into what fix_new_exp wants. */
+ reloc_size = reloc_size / 8;
+ if (reloc_size == 8)
+ reloc_size = 0;
else if (reloc_size == 16)
- reloc = BFD_RELOC_16;
- else if (reloc_size == 8)
- reloc = BFD_RELOC_8;
- else
- abort ();
- }
+ reloc_size = 1;
+ else if (reloc_size == 32)
+ reloc_size = 2;
+
+ fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
+ reloc_size, &fixups[i].exp, pcrel,
+ ((bfd_reloc_code_real_type) reloc));
- /* Convert the size of the reloc into what fix_new_exp wants. */
- reloc_size = reloc_size / 8;
- if (reloc_size == 8)
- reloc_size = 0;
- else if (reloc_size == 16)
- reloc_size = 1;
- else if (reloc_size == 32)
- reloc_size = 2;
-
- fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
- reloc_size, &fixups[i].exp, pcrel,
- ((bfd_reloc_code_real_type) reloc));
-
- if (pcrel)
- fixP->fx_offset += offset;
+ if (pcrel)
+ fixP->fx_offset += offset;
+ }
}
}
}
fixS *fixp;
{
arelent *reloc;
- reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
+ reloc = (arelent *) xmalloc (sizeof (arelent));
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
if (reloc->howto == (reloc_howto_type *) NULL)
fragS *fragp;
asection *seg;
{
- return 0;
+ if (fragp->fr_subtype == 0)
+ return 2;
+ if (fragp->fr_subtype == 3)
+ return 3;
+ if (fragp->fr_subtype == 6)
+ {
+ if (!S_IS_DEFINED (fragp->fr_symbol)
+ || seg != S_GET_SEGMENT (fragp->fr_symbol))
+ {
+ fragp->fr_subtype = 7;
+ return 7;
+ }
+ else
+ return 5;
+ }
+ if (fragp->fr_subtype == 8)
+ {
+ if (!S_IS_DEFINED (fragp->fr_symbol)
+ || seg != S_GET_SEGMENT (fragp->fr_symbol))
+ {
+ fragp->fr_subtype = 9;
+ return 6;
+ }
+ else
+ return 4;
+ }
+ if (fragp->fr_subtype == 10)
+ {
+ if (!S_IS_DEFINED (fragp->fr_symbol)
+ || seg != S_GET_SEGMENT (fragp->fr_symbol))
+ {
+ fragp->fr_subtype = 12;
+ return 5;
+ }
+ else
+ return 2;
+ }
}
long
/* tc-sparc.c -- Assemble for the SPARC
- Copyright (C) 1989, 90-95, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1989, 90-96, 1997 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
subseg_set (bss_section, 1); /* switch to bss */
if (align)
- frag_align (align, 0); /* do alignment */
+ frag_align (align, 0, 0); /* do alignment */
/* detach from old frag */
if (S_GET_SEGMENT(symbolP) == bss_section)
record_alignment (bss_section, align);
subseg_set (bss_section, 0);
if (align)
- frag_align (align, 0);
+ frag_align (align, 0, 0);
if (S_GET_SEGMENT (symbolP) == bss_section)
symbolP->sy_frag->fr_symbol = 0;
symbolP->sy_frag = frag_now;
;
goto allocate_common;
}
+
+#ifdef BFD_ASSEMBLER
+ symbolP->bsym->flags |= BSF_OBJECT;
+#endif
+
demand_empty_rest_of_line ();
return;
arelent *reloc;
bfd_reloc_code_real_type code;
- reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
- assert (reloc != 0);
+ reloc = (arelent *) xmalloc (sizeof (arelent));
reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
fprintf (stream, "\
specify variant of SPARC architecture\n\
-bump warn when assembler switches architectures\n\
--sparc ignored\n
+-sparc ignored\n\
--enforce-aligned-data force .long, etc., to be aligned correctly\n");
#ifdef OBJ_AOUT
fprintf (stream, "\
#ifndef RELOC_EXPANSION_POSSIBLE
/* Set up reloc information as well. */
- relocs = (arelent **) bfd_alloc_by_size_t (stdoutput,
- n * sizeof (arelent *));
+ relocs = (arelent **) xmalloc (n * sizeof (arelent *));
memset ((char*)relocs, 0, n * sizeof (arelent*));
i = 0;
as_bad_where (fixp->fx_file, fixp->fx_line, "relocation overflow");
break;
default:
- as_fatal ("%s:%u: bad return from bfd_perform_relocation",
+ as_fatal ("%s:%u: bad return from bfd_install_relocation",
fixp->fx_file, fixp->fx_line);
}
relocs[i++] = reloc;
#else
n = n * MAX_RELOC_EXPANSION;
/* Set up reloc information as well. */
- relocs = (arelent **) bfd_alloc_by_size_t (stdoutput,
- n * sizeof (arelent *));
+ relocs = (arelent **) xmalloc (stdoutput, n * sizeof (arelent *));
i = 0;
for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
"relocation overflow");
break;
default:
- as_fatal ("%s:%u: bad return from bfd_perform_relocation",
+ as_fatal ("%s:%u: bad return from bfd_install_relocation",
fixp->fx_file, fixp->fx_line);
}
}
for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next)
{
subseg_set (frchainP->frch_seg, frchainP->frch_subseg);
- frag_align (SUB_SEGMENT_ALIGN (now_seg), NOP_OPCODE);
+ frag_align (SUB_SEGMENT_ALIGN (now_seg), NOP_OPCODE, 0);
/* frag_align will have left a new frag.
Use this last frag for an empty ".fill".
case rs_align:
case rs_align_code:
{
- int offset = relax_align (address, (int) fragP->fr_offset);
+ addressT offset = relax_align (address, (int) fragP->fr_offset);
+
+ if (fragP->fr_subtype != 0 && offset > fragP->fr_subtype)
+ offset = 0;
+
if (offset % fragP->fr_var != 0)
{
- as_bad ("alignment padding (%d bytes) not a multiple of %ld",
- offset, (long) fragP->fr_var);
+ as_bad ("alignment padding (%lu bytes) not a multiple of %ld",
+ (unsigned long) offset, (long) fragP->fr_var);
offset -= (offset % fragP->fr_var);
}
+
address += offset;
}
break;
for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next)
{
long growth = 0;
- unsigned long was_address;
- long offset;
+ addressT was_address;
+ offsetT offset;
symbolS *symbolP;
was_address = fragP->fr_address;
#endif
case rs_align:
case rs_align_code:
- growth = (relax_align ((relax_addressT) (address
- + fragP->fr_fix),
- (int) offset)
- - relax_align ((relax_addressT) (was_address
- + fragP->fr_fix),
- (int) offset));
+ {
+ addressT oldoff, newoff;
+
+ oldoff = relax_align (was_address + fragP->fr_fix,
+ (int) offset);
+ newoff = relax_align (address + fragP->fr_fix,
+ (int) offset);
+
+ if (fragP->fr_subtype != 0)
+ {
+ if (oldoff > fragP->fr_subtype)
+ oldoff = 0;
+ if (newoff > fragP->fr_subtype)
+ newoff = 0;
+ }
+
+ growth = newoff - oldoff;
+ }
break;
case rs_org: