aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gas/ChangeLog5
-rw-r--r--gas/as.h38
-rw-r--r--gas/config/obj-coff.c82
-rw-r--r--gas/config/tc-alpha.c781
-rw-r--r--gas/config/tc-arm.c2273
-rw-r--r--gas/config/tc-d10v.c10
-rw-r--r--gas/config/tc-i386.c63
-rw-r--r--gas/config/tc-m68k.c7
-rw-r--r--gas/config/tc-mn10300.c750
-rw-r--r--gas/config/tc-sparc.c16
-rw-r--r--gas/write.c51
11 files changed, 3159 insertions, 917 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 9a924d1..3b0390a 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,8 @@
+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.
diff --git a/gas/as.h b/gas/as.h
index 66d385c..f24b072 100644
--- a/gas/as.h
+++ b/gas/as.h
@@ -1,5 +1,5 @@
/* 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.
@@ -15,8 +15,9 @@
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
@@ -135,6 +136,7 @@ void *alloca ();
#ifdef BFD_ASSEMBLER
#include <bfd.h>
#endif
+#include <libiberty.h>
/* Define the standard progress macros. */
#include <progress.h>
@@ -161,8 +163,8 @@ extern void free ();
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
@@ -171,13 +173,6 @@ extern int errno;
#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
@@ -348,11 +343,17 @@ enum _relax_state
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
@@ -498,6 +499,9 @@ COMMON unsigned char flag_print_statistics;
/* 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;
@@ -541,7 +545,7 @@ typedef struct _pseudo_type pseudo_typeS;
#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)))
@@ -580,8 +584,6 @@ char *atof_ieee PARAMS ((char *str, int what_kind, LITTLENUM_TYPE * words));
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));
diff --git a/gas/config/obj-coff.c b/gas/config/obj-coff.c
index 93ac0ad..315597c 100644
--- a/gas/config/obj-coff.c
+++ b/gas/config/obj-coff.c
@@ -19,6 +19,8 @@
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"
@@ -327,14 +329,14 @@ static symbolS *line_fsym;
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;
}
@@ -364,8 +366,8 @@ add_lineno (frag, offset, num)
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 ();
@@ -882,7 +884,7 @@ obj_coff_val (ignore)
}
void
-obj_read_begin_hook ()
+coff_obj_read_begin_hook ()
{
/* These had better be the same. Usually 18 bytes. */
#ifndef BFD_HEADERS
@@ -1047,7 +1049,7 @@ coff_frob_symbol (symp, punt)
/* 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;
@@ -1120,6 +1122,7 @@ coff_frob_file ()
* '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.
*/
@@ -1176,6 +1179,7 @@ obj_coff_section (ignore)
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 */
@@ -2000,7 +2004,7 @@ symbol_to_chars (abfd, where, symbolP)
}
void
-obj_symbol_new_hook (symbolP)
+coff_obj_symbol_new_hook (symbolP)
symbolS *symbolP;
{
char underscore = 0; /* Symbol has leading _ */
@@ -2571,7 +2575,7 @@ obj_coff_pe_handle_link_once (type)
#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
@@ -2921,7 +2925,7 @@ crawl_symbols (h, abfd)
* 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
@@ -3356,6 +3360,7 @@ obj_coff_add_segment (name)
* '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.
*/
@@ -3420,6 +3425,7 @@ obj_coff_section (ignore)
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);
@@ -4312,6 +4318,7 @@ const pseudo_typeS obj_pseudo_table[] =
{"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. */
@@ -4319,3 +4326,60 @@ const pseudo_typeS obj_pseudo_table[] =
#endif
{NULL} /* end sentinel */
}; /* obj_pseudo_table */
+
+#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
diff --git a/gas/config/tc-alpha.c b/gas/config/tc-alpha.c
index 91879bd..9a17444 100644
--- a/gas/config/tc-alpha.c
+++ b/gas/config/tc-alpha.c
@@ -1,10 +1,10 @@
/* 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.
@@ -87,8 +87,8 @@ enum alpha_macro_arg
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];
};
@@ -154,70 +154,73 @@ struct alpha_macro
/* 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 *));
/* Generic assembler global variables which must be defined by all
@@ -287,7 +290,7 @@ size_t md_longopts_size = sizeof(md_longopts);
#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 */
@@ -317,6 +320,8 @@ static segT alpha_lit4_section;
#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;
@@ -327,9 +332,17 @@ static symbolS *alpha_lit4_symbol;
#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;
@@ -377,21 +390,10 @@ static struct {
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
@@ -434,32 +436,32 @@ static const struct alpha_macro alpha_macros[] = {
{ 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 } },
@@ -513,19 +515,19 @@ static const struct alpha_macro alpha_macros[] = {
{ 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 } },
@@ -539,11 +541,11 @@ static const struct alpha_macro alpha_macros[] = {
{ "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 */ } },
@@ -744,7 +746,7 @@ md_begin ()
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
@@ -894,18 +896,34 @@ md_parse_option (c, arg)
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)
{
@@ -917,8 +935,8 @@ md_parse_option (c, arg)
}
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;
@@ -926,11 +944,7 @@ md_parse_option (c, arg)
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
@@ -958,10 +972,8 @@ Alpha options:\n\
#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
}
@@ -1015,7 +1027,7 @@ md_apply_fix (fixP, valueP)
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;
@@ -1093,12 +1105,13 @@ md_apply_fix (fixP, valueP)
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
@@ -1106,15 +1119,15 @@ md_apply_fix (fixP, valueP)
{
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
@@ -1134,10 +1147,10 @@ md_apply_fix (fixP, valueP)
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);
@@ -1146,7 +1159,7 @@ done:
return 0;
}
-/*
+/*
* Look for a register name in the given symbol.
*/
@@ -1177,7 +1190,7 @@ md_undefined_symbol(name)
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;
}
@@ -1247,11 +1260,17 @@ alpha_force_relocation (f)
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;
@@ -1262,8 +1281,7 @@ alpha_force_relocation (f)
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;
}
}
@@ -1284,10 +1302,37 @@ alpha_fix_adjustable (f)
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*/
}
@@ -1302,13 +1347,13 @@ tc_gen_reloc (sec, 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;
/* 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)
@@ -1337,7 +1382,7 @@ tc_gen_reloc (sec, fixp)
{
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
@@ -1394,12 +1439,12 @@ tokenize_arguments (str, tok, ntok)
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 ();
@@ -1555,7 +1600,7 @@ find_opcode_match(first_opcode, tok, pntok, pcpumatch)
match_failed:;
}
- while (++opcode-alpha_opcodes < alpha_num_opcodes
+ while (++opcode-alpha_opcodes < alpha_num_opcodes
&& !strcmp(opcode->name, first_opcode->name));
if (*pcpumatch)
@@ -1631,7 +1676,7 @@ find_macro_match(first_macro, tok, pntok)
}
++tokidx;
break;
-
+
match_failed:
while (*arg != MACRO_EOA)
++arg;
@@ -1641,7 +1686,7 @@ find_macro_match(first_macro, tok, pntok)
++arg;
}
}
- while (++macro-alpha_macros < alpha_num_macros
+ while (++macro-alpha_macros < alpha_num_macros
&& !strcmp(macro->name, first_macro->name));
return NULL;
@@ -1674,9 +1719,9 @@ insert_operand(insn, operand, val, file, line)
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)
@@ -1690,9 +1735,9 @@ insert_operand(insn, operand, val, file, line)
{
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);
@@ -1700,7 +1745,7 @@ insert_operand(insn, operand, val, file, line)
return insn;
}
-/*
+/*
* Turn an opcode description and a set of arguments into
* an instruction and a fixup.
*/
@@ -1716,7 +1761,7 @@ assemble_insn(opcode, tok, ntok, insn)
unsigned image;
int tokidx = 0;
- memset(insn, 0, sizeof(*insn));
+ memset (insn, 0, sizeof (*insn));
image = opcode->opcode;
for (argidx = opcode->operands; *argidx; ++argidx)
@@ -1786,7 +1831,7 @@ assemble_insn(opcode, tok, ntok, insn)
insn->insn = image;
}
-/*
+/*
* Actually output an instruction with its fixup.
*/
@@ -1816,7 +1861,7 @@ emit_insn (insn)
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. */
@@ -1828,7 +1873,7 @@ emit_insn (insn)
#endif
else
{
- reloc_howto_type *reloc_howto
+ reloc_howto_type *reloc_howto
= bfd_reloc_type_lookup (stdoutput, fixup->reloc);
assert (reloc_howto);
@@ -1844,7 +1889,12 @@ emit_insn (insn)
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;
@@ -1936,7 +1986,7 @@ assemble_tokens (opname, tok, ntok, local_macros_on)
return;
}
}
-
+
if (found_something)
if (cpumatch)
as_bad ("inappropriate arguments for opcode `%s'", opname);
@@ -1956,14 +2006,17 @@ static const char * const extXl_op[] = { "extbl", "extwl", "extll", "extql" };
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
@@ -2004,7 +2057,7 @@ 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
@@ -2140,7 +2193,7 @@ load_expression (targreg, exp, pbasereg, poffset)
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
@@ -2162,7 +2215,7 @@ load_expression (targreg, exp, pbasereg, poffset)
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
@@ -2184,7 +2237,7 @@ load_expression (targreg, exp, pbasereg, poffset)
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;
@@ -2240,6 +2293,7 @@ load_expression (targreg, exp, pbasereg, poffset)
#endif /* OBJ_EVAX */
emit_insn(&insn);
+
#ifndef OBJ_EVAX
emit_lituse = 1;
@@ -2252,6 +2306,7 @@ load_expression (targreg, exp, pbasereg, poffset)
assemble_tokens ("addq", newtok, 3, 0);
}
#endif
+
basereg = targreg;
}
break;
@@ -2283,7 +2338,6 @@ load_expression (targreg, exp, pbasereg, poffset)
/* 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);
@@ -2291,7 +2345,6 @@ load_expression (targreg, exp, pbasereg, poffset)
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)
@@ -2299,14 +2352,20 @@ load_expression (targreg, exp, pbasereg, poffset)
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)
{
@@ -2319,9 +2378,46 @@ load_expression (targreg, exp, pbasereg, poffset)
}
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" */
@@ -2401,7 +2497,7 @@ static void
emit_lda (tok, ntok, unused)
const expressionS *tok;
int ntok;
- void *unused;
+ const PTR unused;
{
int basereg;
@@ -2420,7 +2516,7 @@ static void
emit_ldah (tok, ntok, unused)
const expressionS *tok;
int ntok;
- void *unused;
+ const PTR unused;
{
expressionS newtok[3];
@@ -2439,7 +2535,7 @@ static void
emit_ir_load (tok, ntok, opname)
const expressionS *tok;
int ntok;
- void *opname;
+ const PTR opname;
{
int basereg, lituse;
expressionS newtok[3];
@@ -2473,8 +2569,8 @@ emit_ir_load (tok, ntok, opname)
}
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))
@@ -2491,12 +2587,12 @@ static void
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
@@ -2539,44 +2635,49 @@ emit_loadstore (tok, ntok, opname)
/* 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);
@@ -2589,7 +2690,7 @@ static void
emit_uldXu (tok, ntok, vlgsize)
const expressionS *tok;
int ntok;
- void *vlgsize;
+ const PTR vlgsize;
{
long lgsize = (long)vlgsize;
expressionS newtok[3];
@@ -2599,7 +2700,7 @@ emit_uldXu (tok, ntok, vlgsize)
/* 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);
@@ -2636,7 +2737,7 @@ emit_uldXu (tok, ntok, vlgsize)
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. */
@@ -2645,7 +2746,7 @@ static void
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);
@@ -2657,7 +2758,7 @@ static void
emit_ldil (tok, ntok, unused)
const expressionS *tok;
int ntok;
- void *unused;
+ const PTR unused;
{
expressionS newtok[2];
@@ -2672,50 +2773,57 @@ emit_ldil (tok, ntok, unused)
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. */
@@ -2724,14 +2832,14 @@ static void
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);
@@ -2807,22 +2915,29 @@ static void
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. */
@@ -2832,11 +2947,11 @@ emit_sextX (tok, ntok, vlgsize)
/* 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.
*
@@ -2850,7 +2965,7 @@ emit_division (tok, ntok, symname)
* 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;
@@ -2859,7 +2974,7 @@ emit_division (tok, ntok, symname)
xr = regno (tok[0].X_add_number);
yr = regno (tok[1].X_add_number);
-
+
if (ntok < 3)
rr = xr;
else
@@ -2932,11 +3047,11 @@ emit_division (tok, ntok, symname)
#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
@@ -2949,7 +3064,7 @@ emit_division (tok, ntok, symname)
* 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;
@@ -2958,7 +3073,7 @@ emit_division (tok, ntok, symname)
xr = regno (tok[0].X_add_number);
yr = regno (tok[1].X_add_number);
-
+
if (ntok < 3)
rr = xr;
else
@@ -3045,7 +3160,7 @@ static void
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;
@@ -3102,7 +3217,7 @@ emit_jsrjmp (tok, ntok, vopname)
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. */
@@ -3123,7 +3238,7 @@ static void
emit_retjcr (tok, ntok, vopname)
const expressionS *tok;
int ntok;
- void *vopname;
+ const PTR vopname;
{
const char *opname = (const char *)vopname;
expressionS newtok[3];
@@ -3166,7 +3281,7 @@ s_alpha_text (i)
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. */
@@ -3179,9 +3294,9 @@ s_alpha_data (i)
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. */
@@ -3228,27 +3343,6 @@ s_alpha_comm (ignore)
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)
@@ -3263,16 +3357,14 @@ s_alpha_comm (ignore)
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. */
@@ -3318,7 +3410,7 @@ s_alpha_sdata (ignore)
/* 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;
{
@@ -3329,17 +3421,29 @@ s_alpha_section (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;
@@ -3514,7 +3618,7 @@ s_alpha_pdesc (ignore)
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;
@@ -3585,6 +3689,47 @@ s_alpha_pdesc (ignore)
}
+/* 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;
@@ -3615,6 +3760,35 @@ s_alpha_linkage (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;
{
@@ -3689,17 +3863,14 @@ static void
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;
@@ -4004,19 +4175,48 @@ alpha_cons_align (size)
alpha_insn_label = NULL;
}
+
+#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
+
/* 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
@@ -4028,15 +4228,22 @@ const pseudo_typeS md_pseudo_table[] =
#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'},
@@ -4173,14 +4380,14 @@ alpha_align (n, pfill, label)
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;
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 2ea147d..644d89b 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -1,10 +1,8 @@
-/* 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
@@ -18,8 +16,9 @@
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>
@@ -45,13 +44,14 @@
#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
@@ -103,13 +103,21 @@ CONST char EXP_CHARS[] = "eE";
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;
@@ -171,6 +179,8 @@ LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
#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
@@ -202,102 +212,133 @@ static CONST struct asm_cond conds[] =
{"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 ldst_flags[] =
+static CONST struct asm_flg ldr_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", 0x801000b0},
+ {"sh", 0x801000f0},
+ {"sb", 0x801000d0},
+ {NULL, 0}
+};
+
+static CONST struct asm_flg str_flags[] =
+{
+ {"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
@@ -343,6 +384,8 @@ static void do_msr PARAMS ((char *operands, unsigned long flags));
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));
@@ -364,12 +407,12 @@ static int arm_reg_parse PARAMS ((char **ccp));
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
@@ -403,13 +446,13 @@ static CONST struct asm_opcode insns[] =
{"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},
@@ -432,6 +475,9 @@ static CONST struct asm_opcode insns[] =
{"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},
@@ -478,7 +524,7 @@ static CONST struct asm_opcode insns[] =
{"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},
@@ -523,6 +569,176 @@ static CONST struct asm_opcode insns[] =
#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;
@@ -534,20 +750,22 @@ struct reg_entry
#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},
@@ -566,6 +784,7 @@ static CONST char *bad_args = "Bad arguments to instruction";
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;
@@ -583,6 +802,9 @@ static void s_align PARAMS ((int));
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 **));
@@ -591,6 +813,9 @@ CONST pseudo_typeS md_pseudo_table[] =
{"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},
@@ -668,7 +893,7 @@ add_to_lit_pool ()
}
/* 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;
@@ -807,7 +1032,7 @@ s_even (ignore)
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 ();
}
@@ -830,7 +1055,7 @@ s_ltorg (internal)
/* 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);
@@ -859,7 +1084,7 @@ arm_align (power, fill)
{
/* 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);
}
@@ -895,13 +1120,83 @@ s_align (unused) /* Same as s_align_ptwo but align 0 => align 2 */
/* 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;
{
@@ -1724,7 +2019,8 @@ decode_shift (str, unrestrict)
*p = c;
if (shft)
{
- if (!strcmp (*str, "rrx"))
+ if (!strcmp (*str, "rrx")
+ || !strcmp (*str, "RRX"))
{
*str = p;
inst.instruction |= shft->value;
@@ -1748,12 +2044,12 @@ decode_shift (str, unrestrict)
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;
@@ -2060,8 +2356,8 @@ do_adr (str, flags)
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++;
@@ -2109,7 +2405,7 @@ do_cmp (str, flags)
inst.instruction |= flags;
if ((flags & 0x0000f000) == 0)
- inst.instruction |= 0x00100000;
+ inst.instruction |= CONDS_BIT;
end_of_line (str);
return;
@@ -2208,12 +2504,12 @@ ldst_extend (str, hwse)
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;
}
}
@@ -2224,28 +2520,28 @@ do_ldst (str, flags)
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 == ' ')
@@ -2279,7 +2575,7 @@ do_ldst (str, flags)
}
conflict_reg = (((conflict_reg == reg)
- && (inst.instruction & 0x00100000))
+ && (inst.instruction & LOAD_BIT))
? 1 : 0);
while (*str == ' ')
@@ -2291,7 +2587,7 @@ do_ldst (str, flags)
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");
@@ -2299,7 +2595,7 @@ do_ldst (str, flags)
else
{
/* [Rn] */
- if (halfword | signextend)
+ if (halfword)
inst.instruction |= HWOFFSET_IMM;
while (*str == ' ')
@@ -2328,7 +2624,7 @@ do_ldst (str, flags)
}
pre_inc = 1;
- if (ldst_extend (&str, halfword | signextend) == FAIL)
+ if (ldst_extend (&str, halfword) == FAIL)
return;
while (*str == ' ')
@@ -2346,7 +2642,7 @@ do_ldst (str, flags)
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;
}
@@ -2391,7 +2687,7 @@ do_ldst (str, flags)
}
/* 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;
@@ -2408,7 +2704,7 @@ do_ldst (str, flags)
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;
@@ -2429,155 +2725,175 @@ do_ldst (str, flags)
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 (in_range)
+ if (my_get_expression (&expr, &str))
+ return FAIL;
+
+ 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);
}
- in_range = 0;
+
+ range |= expr.X_add_number;
}
+ else
+ {
+ if (inst.reloc.type != 0)
+ {
+ inst.error = "expression too complex";
+ return FAIL;
+ }
+
+ 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 == '^')
@@ -2585,7 +2901,8 @@ do_ldmstm (str, flags)
str++;
flags |= MULTI_SET_PSR;
}
- inst.instruction |= flags;
+
+ inst.instruction |= flags | range;
end_of_line (str);
return;
}
@@ -2686,7 +3003,26 @@ do_branch (str, flags)
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;
}
@@ -3257,6 +3593,915 @@ do_fp_to_reg (str, flags)
return;
}
+/* 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 reg;
+
+ if ((reg = arm_reg_parse (strp)) == FAIL || ! int_register (reg))
+ {
+ inst.error = "Register expected";
+ return FAIL;
+ }
+
+ switch (hi_lo)
+ {
+ case THUMB_REG_LO:
+ if (reg > 7)
+ {
+ inst.error = "lo register required";
+ return FAIL;
+ }
+ break;
+
+ 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;
@@ -3313,6 +4558,7 @@ md_begin ()
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
@@ -3321,6 +4567,8 @@ md_begin ()
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++)
@@ -3577,6 +4825,7 @@ md_apply_fix3 (fixP, val, seg)
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);
@@ -3600,7 +4849,7 @@ md_apply_fix3 (fixP, val, seg)
{
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. */
@@ -3613,7 +4862,7 @@ md_apply_fix3 (fixP, val, seg)
}
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:
@@ -3626,10 +4875,10 @@ md_apply_fix3 (fixP, val, seg)
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:
@@ -3648,10 +4897,10 @@ md_apply_fix3 (fixP, val, seg)
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:
@@ -3666,14 +4915,14 @@ md_apply_fix3 (fixP, val, seg)
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)))
@@ -3689,31 +4938,98 @@ md_apply_fix3 (fixP, val, seg)
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:
@@ -3739,9 +5055,151 @@ md_apply_fix3 (fixP, val, seg)
"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:
@@ -3763,8 +5221,7 @@ tc_gen_reloc (section, fixp)
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;
@@ -3845,6 +5302,11 @@ tc_gen_reloc (section, fixp)
, 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 ();
}
@@ -3900,12 +5362,19 @@ output_inst (str)
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;
@@ -3916,7 +5385,6 @@ md_assemble (str)
char *str;
{
char c;
- CONST struct asm_opcode *opcode;
char *p, *q, *start;
/* Align the instruction */
@@ -3950,130 +5418,153 @@ md_assemble (str)
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
*/
@@ -4156,7 +5647,7 @@ struct option md_longopts[] = {
#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)
@@ -4195,6 +5686,18 @@ 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"))
{
@@ -4246,7 +5749,7 @@ md_parse_option (c, arg)
switch (*str)
{
case 't':
- cpu_variant |= ARM_HALFWORD;
+ cpu_variant |= ARM_THUMB;
break;
case 'm':
@@ -4286,7 +5789,7 @@ md_show_usage (fp)
{
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\
@@ -4315,6 +5818,7 @@ fix_new_arm (frag, where, size, exp, pc_rel, reloc)
int reloc;
{
fixS *new_fix;
+ arm_fix_data *arm_data;
switch (exp->X_op)
{
@@ -4326,25 +5830,16 @@ fix_new_arm (frag, where, size, exp, pc_rel, reloc)
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 (&notes, sizeof (arm_fix_data));
+ new_fix->tc_fix_data = (PTR) arm_data;
+ arm_data->thumb_mode = thumb_mode;
+
return;
}
@@ -4375,3 +5870,31 @@ arm_frob_label (sym)
{
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;
+}
diff --git a/gas/config/tc-d10v.c b/gas/config/tc-d10v.c
index 0ade942..28519c7 100644
--- a/gas/config/tc-d10v.c
+++ b/gas/config/tc-d10v.c
@@ -95,7 +95,7 @@ const pseudo_typeS md_pseudo_table[] =
/* 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. */
@@ -107,18 +107,18 @@ reg_name_search (name)
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;
@@ -1225,7 +1225,7 @@ tc_gen_reloc (seg, fixp)
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);
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index d07764e..7f04277 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -104,7 +104,7 @@ typedef struct _i386_insn i386_insn;
/* 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[] = "#";
@@ -118,7 +118,7 @@ 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[] = "/";
@@ -577,10 +577,13 @@ md_begin ()
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
}
@@ -2653,11 +2656,13 @@ md_apply_fix3 (fixP, valp, seg)
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
@@ -2670,8 +2675,9 @@ md_apply_fix3 (fixP, valp, seg)
/* 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
@@ -2860,7 +2866,7 @@ md_parse_option (c, arg)
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;
@@ -2889,9 +2895,32 @@ md_show_usage (stream)
fprintf (stream, "\
-m do long jump\n");
}
-
-/* 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 */
+
/* ARGSUSED */
symbolS *
md_undefined_symbol (name)
@@ -3001,9 +3030,7 @@ tc_gen_reloc (section, fixp)
&& 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)
diff --git a/gas/config/tc-m68k.c b/gas/config/tc-m68k.c
index 4ee9f8a..ec92ca2 100644
--- a/gas/config/tc-m68k.c
+++ b/gas/config/tc-m68k.c
@@ -44,7 +44,7 @@ const char *m68k_comment_chars = "|";
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[] = "";
@@ -856,8 +856,7 @@ tc_gen_reloc (section, fixp)
#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
@@ -904,7 +903,6 @@ m68k_ip (instring)
char c;
int losing;
int opsfound;
- char *crack_operand ();
LITTLENUM_TYPE words[6];
LITTLENUM_TYPE *wordp;
unsigned long ok_arch = 0;
@@ -3370,6 +3368,7 @@ md_assemble (str)
n = 1;
break;
case 'w':
+ case 'W':
n = 2;
break;
case 'l':
diff --git a/gas/config/tc-mn10300.c b/gas/config/tc-mn10300.c
index a86b2db..9c9db9a 100644
--- a/gas/config/tc-mn10300.c
+++ b/gas/config/tc-mn10300.c
@@ -1,6 +1,6 @@
/* 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.
@@ -53,6 +53,32 @@ const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "dD";
+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 *,
@@ -361,8 +387,285 @@ md_convert_frag (abfd, sec, fragP)
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
@@ -412,7 +715,7 @@ md_assemble (str)
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;
@@ -445,6 +748,7 @@ md_assemble (str)
char *hold;
int extra_shift = 0;
+ relaxable = 0;
fc = 0;
match = 0;
next_opindex = 0;
@@ -472,6 +776,9 @@ md_assemble (str)
while (*str == ' ' || *str == ',')
++str;
+ if (operand->flags & MN10300_OPERAND_RELAX)
+ relaxable = 1;
+
/* Gather the operand. */
hold = input_line_pointer;
input_line_pointer = str;
@@ -686,7 +993,8 @@ md_assemble (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;
@@ -778,192 +1086,244 @@ keep_going:
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;
+ }
}
}
}
@@ -978,7 +1338,7 @@ tc_gen_reloc (seg, fixp)
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)
@@ -1009,7 +1369,43 @@ md_estimate_size_before_relax (fragp, seg)
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
diff --git a/gas/config/tc-sparc.c b/gas/config/tc-sparc.c
index 00a961d..49b5ee6 100644
--- a/gas/config/tc-sparc.c
+++ b/gas/config/tc-sparc.c
@@ -1,5 +1,5 @@
/* 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.
@@ -355,7 +355,7 @@ s_reserve (ignore)
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)
@@ -472,7 +472,7 @@ s_common (ignore)
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;
@@ -515,6 +515,11 @@ s_common (ignore)
;
goto allocate_common;
}
+
+#ifdef BFD_ASSEMBLER
+ symbolP->bsym->flags |= BSF_OBJECT;
+#endif
+
demand_empty_rest_of_line ();
return;
@@ -2613,8 +2618,7 @@ tc_gen_reloc (section, fixp)
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;
@@ -2972,7 +2976,7 @@ md_show_usage (stream)
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, "\
diff --git a/gas/write.c b/gas/write.c
index a67b34a..e737075 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -851,8 +851,7 @@ write_relocs (abfd, sec, xxx)
#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;
@@ -913,7 +912,7 @@ write_relocs (abfd, sec, xxx)
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;
@@ -921,8 +920,7 @@ write_relocs (abfd, sec, xxx)
#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)
@@ -975,7 +973,7 @@ write_relocs (abfd, sec, xxx)
"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);
}
}
@@ -1339,7 +1337,7 @@ write_object_file ()
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".
@@ -2037,13 +2035,18 @@ relax_segment (segment_frag_root, segment)
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;
@@ -2086,8 +2089,8 @@ relax_segment (segment_frag_root, segment)
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;
@@ -2164,12 +2167,24 @@ relax_segment (segment_frag_root, segment)
#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: