/* tc-m68k.c -- Assemble for the m68k family
- Copyright (C) 1987, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 91, 92, 93, 94, 95, 96, 1997
+ Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
02111-1307, USA. */
#include <ctype.h>
-#define NO_RELOC 0
#include "as.h"
#include "obstack.h"
#include "subsegs.h"
#include "opcode/m68k.h"
#include "m68k-parse.h"
-/* This array holds the chars that always start a comment. If the
- pre-processor is disabled, these aren't very useful */
-#if defined (OBJ_ELF) || defined (TE_DELTA)
-const char comment_chars[] = "|#";
+/* This string holds the chars that always start a comment. If the
+ pre-processor is disabled, these aren't very useful. The macro
+ tc_comment_chars points to this. We use this, rather than the
+ usual comment_chars, so that the --bitwise-or option will work. */
+#if (defined (OBJ_ELF) && ! defined (TE_PSOS) && ! defined (TE_LINUX)) || defined (TE_DELTA)
+const char *m68k_comment_chars = "|#";
#else
-const char comment_chars[] = "|";
+const char *m68k_comment_chars = "|";
#endif
/* This array holds the chars that only start a comment at the beginning of
/* Are we trying to generate PIC code? If so, absolute references
ought to be made into linkage table references or pc-relative
- references. */
+ references. Not implemented. For ELF there are other means
+ to denote pic relocations. */
int flag_want_pic;
static int flag_short_refs; /* -l option */
int flag_reg_prefix_optional;
#endif
+/* Whether --register-prefix-optional was used on the command line. */
+static int reg_prefix_optional_seen;
+
/* The floating point coprocessor to use by default. */
static enum m68k_register m68k_float_copnum = COP1;
be 32 bits. */
static int m68k_rel32 = 1;
+/* This is non-zero if m68k_rel32 was set from the command line. */
+static int m68k_rel32_from_cmdline;
+
+/* The default width to use for an index register when using a base
+ displacement. */
+static enum m68k_size m68k_index_width_default = SIZE_LONG;
+
+/* We want to warn if any text labels are misaligned. In order to get
+ the right line number, we need to record the line number for each
+ label. */
+
+struct label_line
+{
+ struct label_line *next;
+ symbolS *label;
+ char *file;
+ unsigned int line;
+ int text;
+};
+
+/* The list of labels. */
+
+static struct label_line *labels;
+
+/* The current label. */
+
+static struct label_line *current_label;
+
/* Its an arbitrary name: This means I don't approve of it */
/* See flames below */
static struct obstack robyn;
USP, VBR, URP, SRP, PCR,
0
};
+static const enum m68k_register mcf5200_control_regs[] = {
+ CACR, TC, ITT0, ITT1, DTT0, DTT1, VBR, ROMBAR,
+ RAMBAR0, RAMBAR1, MBAR,
+ 0
+};
#define cpu32_control_regs m68010_control_regs
static const enum m68k_register *control_regs;
significance of some values (in the branch instruction, for
example). */
int pcrel_fix;
+#ifdef OBJ_ELF
+ /* Whether this expression needs special pic relocation, and if
+ so, which. */
+ enum pic_relocation pic_reloc;
+#endif
}
reloc[5]; /* Five is enough??? */
};
-#define cpu_of_arch(x) ((x) & m68000up)
+#define cpu_of_arch(x) ((x) & (m68000up|mcf5200))
#define float_of_arch(x) ((x) & mfloat)
#define mmu_of_arch(x) ((x) & mmmu)
int pc_rel;
int pc_fix;
{
- the_ins.reloc[the_ins.nrel].n = (((width)=='B')
+ the_ins.reloc[the_ins.nrel].n = ((width == 'B' || width == '3')
? (the_ins.numo*2-1)
: (((width)=='b')
? (the_ins.numo*2+1)
the_ins.reloc[the_ins.nrel].exp = exp->exp;
the_ins.reloc[the_ins.nrel].wid = width;
the_ins.reloc[the_ins.nrel].pcrel_fix = pc_fix;
+#ifdef OBJ_ELF
+ the_ins.reloc[the_ins.nrel].pic_reloc = exp->pic_reloc;
+#endif
the_ins.reloc[the_ins.nrel++].pcrel = pc_rel;
}
struct m68k_cpu {
unsigned long arch;
const char *name;
+ int alias;
};
static const struct m68k_cpu archs[] = {
- { m68000, "68000" },
- { m68010, "68010" },
- { m68020, "68020" },
- { m68030, "68030" },
- { m68040, "68040" },
- { m68060, "68060" },
- { cpu32, "cpu32" },
- { m68881, "68881" },
- { m68851, "68851" },
+ { m68000, "68000", 0 },
+ { m68010, "68010", 0 },
+ { m68020, "68020", 0 },
+ { m68030, "68030", 0 },
+ { m68040, "68040", 0 },
+ { m68060, "68060", 0 },
+ { cpu32, "cpu32", 0 },
+ { m68881, "68881", 0 },
+ { m68851, "68851", 0 },
+ { mcf5200, "5200", 0 },
/* Aliases (effectively, so far as gas is concerned) for the above
cpus. */
- { m68020, "68k" },
- { m68000, "68302" },
- { m68000, "68008" },
- { m68000, "68ec000" },
- { m68000, "68hc000" },
- { m68000, "68hc001" },
- { m68020, "68ec020" },
- { m68030, "68ec030" },
- { m68040, "68ec040" },
- { cpu32, "68330" },
- { cpu32, "68331" },
- { cpu32, "68332" },
- { cpu32, "68333" },
- { cpu32, "68340" },
- { cpu32, "68360" },
- { m68881, "68882" },
+ { m68020, "68k", 1 },
+ { m68000, "68302", 1 },
+ { m68000, "68008", 1 },
+ { m68000, "68ec000", 1 },
+ { m68000, "68hc000", 1 },
+ { m68000, "68hc001", 1 },
+ { m68020, "68ec020", 1 },
+ { m68030, "68ec030", 1 },
+ { m68040, "68ec040", 1 },
+ { m68060, "68ec060", 1 },
+ { cpu32, "68330", 1 },
+ { cpu32, "68331", 1 },
+ { cpu32, "68332", 1 },
+ { cpu32, "68333", 1 },
+ { cpu32, "68340", 1 },
+ { cpu32, "68360", 1 },
+ { m68881, "68882", 1 },
};
static const int n_archs = sizeof (archs) / sizeof (archs[0]);
{"even", s_even, 0},
{"skip", s_space, 0},
{"proc", s_proc, 0},
-#ifdef TE_SUN3
+#if defined (TE_SUN3) || defined (OBJ_ELF)
{"align", s_align_bytes, 0},
#endif
#ifdef OBJ_ELF
{"swbeg", s_ignore, 0},
#endif
+ {"extend", float_cons, 'x'},
+ {"ldouble", float_cons, 'x'},
/* The following pseudo-ops are supported for MRI compatibility. */
{"chip", s_chip, 0},
{"dsb", s_space, 1},
{"xdef", s_globl, 0},
+#ifdef OBJ_ELF
+ {"align", s_align_bytes, 0},
+#else
{"align", s_align_ptwo, 0},
+#endif
#ifdef M68KCOFF
{"sect", obj_coff_section, 0},
{"section", obj_coff_section, 0},
#endif
+#ifdef OBJ_ELF
+
+/* Compute the relocation code for a fixup of SIZE bytes, using pc
+ relative relocation if PCREL is non-zero. PIC says whether a special
+ pic relocation was requested. */
+
+static bfd_reloc_code_real_type get_reloc_code
+ PARAMS ((int, int, enum pic_relocation));
+
+static bfd_reloc_code_real_type
+get_reloc_code (size, pcrel, pic)
+ int size;
+ int pcrel;
+ enum pic_relocation pic;
+{
+ switch (pic)
+ {
+ case pic_got_pcrel:
+ switch (size)
+ {
+ case 1:
+ return BFD_RELOC_8_GOT_PCREL;
+ case 2:
+ return BFD_RELOC_16_GOT_PCREL;
+ case 4:
+ return BFD_RELOC_32_GOT_PCREL;
+ }
+ break;
+
+ case pic_got_off:
+ switch (size)
+ {
+ case 1:
+ return BFD_RELOC_8_GOTOFF;
+ case 2:
+ return BFD_RELOC_16_GOTOFF;
+ case 4:
+ return BFD_RELOC_32_GOTOFF;
+ }
+ break;
+
+ case pic_plt_pcrel:
+ switch (size)
+ {
+ case 1:
+ return BFD_RELOC_8_PLT_PCREL;
+ case 2:
+ return BFD_RELOC_16_PLT_PCREL;
+ case 4:
+ return BFD_RELOC_32_PLT_PCREL;
+ }
+ break;
+
+ case pic_plt_off:
+ switch (size)
+ {
+ case 1:
+ return BFD_RELOC_8_PLTOFF;
+ case 2:
+ return BFD_RELOC_16_PLTOFF;
+ case 4:
+ return BFD_RELOC_32_PLTOFF;
+ }
+ break;
+
+ case pic_none:
+ if (pcrel)
+ {
+ switch (size)
+ {
+ case 1:
+ return BFD_RELOC_8_PCREL;
+ case 2:
+ return BFD_RELOC_16_PCREL;
+ case 4:
+ return BFD_RELOC_32_PCREL;
+ }
+ }
+ else
+ {
+ switch (size)
+ {
+ case 1:
+ return BFD_RELOC_8;
+ case 2:
+ return BFD_RELOC_16;
+ case 4:
+ return BFD_RELOC_32;
+ }
+ }
+ }
+
+ as_bad ("Can not do %d byte %s%srelocation", size,
+ pcrel ? "pc-relative " : "",
+ pic == pic_none ? "" : "pic ");
+ return BFD_RELOC_NONE;
+}
+
+/* Here we decide which fixups can be adjusted to make them relative
+ to the beginning of the section instead of the symbol. Basically
+ we need to make sure that the dynamic relocations are done
+ correctly, so in some cases we force the original symbol to be
+ used. */
+int
+tc_m68k_fix_adjustable (fixP)
+ fixS *fixP;
+{
+ /* Prevent all adjustments to global symbols. */
+ if (S_IS_EXTERNAL (fixP->fx_addsy))
+ return 0;
+
+ /* adjust_reloc_syms doesn't know about the GOT */
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_8_GOT_PCREL:
+ case BFD_RELOC_16_GOT_PCREL:
+ case BFD_RELOC_32_GOT_PCREL:
+ case BFD_RELOC_8_GOTOFF:
+ case BFD_RELOC_16_GOTOFF:
+ case BFD_RELOC_32_GOTOFF:
+ case BFD_RELOC_8_PLT_PCREL:
+ case BFD_RELOC_16_PLT_PCREL:
+ case BFD_RELOC_32_PLT_PCREL:
+ case BFD_RELOC_8_PLTOFF:
+ case BFD_RELOC_16_PLTOFF:
+ case BFD_RELOC_32_PLTOFF:
+ return 0;
+
+ default:
+ return 1;
+ }
+}
+
+#else /* !OBJ_ELF */
+
+#define get_reloc_code(SIZE,PCREL,OTHER) NO_RELOC
+
+#endif /* OBJ_ELF */
+
#ifdef BFD_ASSEMBLER
arelent *
arelent *reloc;
bfd_reloc_code_real_type code;
- if (fixP->fx_tcbit)
+ if (fixp->fx_tcbit)
abort ();
-#define F(SZ,PCREL) (((SZ) << 1) + (PCREL))
- switch (F (fixp->fx_size, fixp->fx_pcrel))
+ if (fixp->fx_r_type != BFD_RELOC_NONE)
{
+ code = fixp->fx_r_type;
+
+ /* Since DIFF_EXPR_OK is defined in tc-m68k.h, it is possible
+ that fixup_segment converted a non-PC relative reloc into a
+ PC relative reloc. In such a case, we need to convert the
+ reloc code. */
+ if (fixp->fx_pcrel)
+ {
+ switch (code)
+ {
+ case BFD_RELOC_8:
+ code = BFD_RELOC_8_PCREL;
+ break;
+ case BFD_RELOC_16:
+ code = BFD_RELOC_16_PCREL;
+ break;
+ case BFD_RELOC_32:
+ code = BFD_RELOC_32_PCREL;
+ break;
+ case BFD_RELOC_8_PCREL:
+ case BFD_RELOC_16_PCREL:
+ case BFD_RELOC_32_PCREL:
+ case BFD_RELOC_8_GOT_PCREL:
+ case BFD_RELOC_16_GOT_PCREL:
+ case BFD_RELOC_32_GOT_PCREL:
+ case BFD_RELOC_8_GOTOFF:
+ case BFD_RELOC_16_GOTOFF:
+ case BFD_RELOC_32_GOTOFF:
+ case BFD_RELOC_8_PLT_PCREL:
+ case BFD_RELOC_16_PLT_PCREL:
+ case BFD_RELOC_32_PLT_PCREL:
+ case BFD_RELOC_8_PLTOFF:
+ case BFD_RELOC_16_PLTOFF:
+ case BFD_RELOC_32_PLTOFF:
+ break;
+ default:
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ "Cannot make %s relocation PC relative",
+ bfd_get_reloc_code_name (code));
+ }
+ }
+ }
+ else
+ {
+#define F(SZ,PCREL) (((SZ) << 1) + (PCREL))
+ switch (F (fixp->fx_size, fixp->fx_pcrel))
+ {
#define MAP(SZ,PCREL,TYPE) case F(SZ,PCREL): code = (TYPE); break
- MAP (1, 0, BFD_RELOC_8);
- MAP (2, 0, BFD_RELOC_16);
- MAP (4, 0, BFD_RELOC_32);
- MAP (1, 1, BFD_RELOC_8_PCREL);
- MAP (2, 1, BFD_RELOC_16_PCREL);
- MAP (4, 1, BFD_RELOC_32_PCREL);
- default:
- abort ();
+ MAP (1, 0, BFD_RELOC_8);
+ MAP (2, 0, BFD_RELOC_16);
+ MAP (4, 0, BFD_RELOC_32);
+ MAP (1, 1, BFD_RELOC_8_PCREL);
+ MAP (2, 1, BFD_RELOC_16_PCREL);
+ MAP (4, 1, BFD_RELOC_32_PCREL);
+ default:
+ abort ();
+ }
}
+#undef F
+#undef MAP
reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
assert (reloc != 0);
reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+#ifndef OBJ_ELF
if (fixp->fx_pcrel)
reloc->addend = fixp->fx_addnumber;
else
reloc->addend = 0;
+#else
+ if (!fixp->fx_pcrel)
+ reloc->addend = fixp->fx_addnumber;
+ else
+ reloc->addend = (section->vma
+ + (fixp->fx_pcrel_adjust == 64
+ ? -1 : fixp->fx_pcrel_adjust)
+ + fixp->fx_addnumber
+ + md_pcrel_from (fixp));
+#endif
reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
assert (reloc->howto != 0);
/* If we didn't get the right number of ops, or we have no
common model with this pattern then reject this pattern. */
+ ok_arch |= opcode->m_arch;
if (opsfound != opcode->m_opnum
|| ((opcode->m_arch & current_architecture) == 0))
- {
- ++losing;
- ok_arch |= opcode->m_arch;
- }
+ ++losing;
else
{
for (s = opcode->m_operands, opP = &the_ins.operands[0];
}
break;
+ case '<':
+ switch (opP->mode)
+ {
+ case DREG:
+ case AREG:
+ case FPREG:
+ case CONTROL:
+ case IMMED:
+ case ADEC:
+ case REGLST:
+ losing++;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case '>':
+ switch (opP->mode)
+ {
+ case DREG:
+ case AREG:
+ case FPREG:
+ case CONTROL:
+ case IMMED:
+ case AINC:
+ case REGLST:
+ losing++;
+ break;
+ case ABSL:
+ break;
+ default:
+ if (opP->reg == PC
+ || opP->reg == ZPC)
+ losing++;
+ break;
+ }
+ break;
+
+ case 'm':
+ switch (opP->mode)
+ {
+ case DREG:
+ case AREG:
+ case AINDR:
+ case AINC:
+ case ADEC:
+ break;
+ default:
+ losing++;
+ }
+ break;
+
+ case 'n':
+ switch (opP->mode)
+ {
+ case DISP:
+ break;
+ default:
+ losing++;
+ }
+ break;
+
+ case 'o':
+ switch (opP->mode)
+ {
+ case BASE:
+ case ABSL:
+ case IMMED:
+ break;
+ default:
+ losing++;
+ }
+ break;
+
+ case 'p':
+ switch (opP->mode)
+ {
+ case DREG:
+ case AREG:
+ case AINDR:
+ case AINC:
+ case ADEC:
+ case DISP:
+ break;
+ default:
+ losing++;
+ }
+ break;
+
case '#':
if (opP->mode != IMMED)
losing++;
&& (opP->disp.exp.X_op != O_constant
|| ! isbyte (opP->disp.exp.X_add_number)))
losing++;
+ else if (s[1] == 'B'
+ && ! isvar (&opP->disp)
+ && (opP->disp.exp.X_op != O_constant
+ || ! issbyte (opP->disp.exp.X_add_number)))
+ losing++;
else if (s[1] == 'w'
&& ! isvar (&opP->disp)
&& (opP->disp.exp.X_op != O_constant
|| ! isword (opP->disp.exp.X_add_number)))
losing++;
+ else if (s[1] == 'W'
+ && ! isvar (&opP->disp)
+ && (opP->disp.exp.X_op != O_constant
+ || ! issword (opP->disp.exp.X_add_number)))
+ losing++;
break;
case '^':
break;
case 'O':
- if (opP->mode != DREG && opP->mode != IMMED)
+ if (opP->mode != DREG
+ && opP->mode != IMMED
+ && opP->mode != ABSL)
losing++;
break;
&& !(ok_arch & current_architecture))
{
char buf[200], *cp;
- int len;
+
strcpy (buf,
"invalid instruction for this architecture; needs ");
cp = buf + strlen (buf);
for (idx = 0; idx < sizeof (archs) / sizeof (archs[0]);
idx++)
{
- if (archs[idx].arch & ok_arch)
+ if ((archs[idx].arch & ok_arch)
+ && ! archs[idx].alias)
{
if (got_one)
{
}
}
}
- len = cp - buf + 1;
- cp = malloc (len);
+ cp = xmalloc (strlen (buf) + 1);
strcpy (cp, buf);
the_ins.error = cp;
}
case '?':
case '/':
case '`':
+ case '<':
+ case '>':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
#ifndef NO_68851
case '|':
#endif
addword (nextword);
baseo = 0;
break;
+ case 'W':
+ if (!issword (nextword))
+ opP->error = "operand out of range";
+ addword (nextword);
+ baseo = 0;
+ break;
case 'l':
addword (nextword >> 16);
addword (nextword);
&& cpu_of_arch (current_architecture) >= m68020)
|| opP->disp.size == SIZE_LONG)))
{
+ if (cpu_of_arch (current_architecture) < m68020)
+ opP->error =
+ "displacement too large for this architecture; needs 68020 or higher";
if (opP->reg == PC)
tmpreg = 0x3B; /* 7.3 */
else
{
if (opP->reg == PC)
{
-#if 0
- addword (0x0170);
- add_fix ('l', &opP->disp, 1, 2);
- addword (0), addword (0);
-#else
- add_frag (adds (&opP->disp),
- offs (&opP->disp),
- TAB (PCLEA, SZ_UNDEF));
+ if (opP->disp.size == SIZE_LONG
+#ifdef OBJ_ELF
+ /* If the displacement needs pic
+ relocation it cannot be relaxed. */
+ || opP->disp.pic_reloc != pic_none
#endif
- break;
+ )
+ {
+ addword (0x0170);
+ add_fix ('l', &opP->disp, 1, 2);
+ }
+ else
+ {
+ add_frag (adds (&opP->disp),
+ offs (&opP->disp),
+ TAB (PCLEA, SZ_UNDEF));
+ break;
+ }
}
else
{
{
nextword |= (opP->index.reg - DATA) << 12;
- if (opP->index.size == SIZE_UNSPEC
- || opP->index.size == SIZE_LONG)
+ if (opP->index.size == SIZE_LONG
+ || (opP->index.size == SIZE_UNSPEC
+ && m68k_index_width_default == SIZE_LONG))
nextword |= 0x800;
- if (cpu_of_arch (current_architecture) < m68020)
+ if ((opP->index.scale != 1
+ && cpu_of_arch (current_architecture) < m68020)
+ || (opP->index.scale == 8
+ && current_architecture == mcf5200))
{
- if (opP->index.scale != 1)
- {
- opP->error =
- "scale factor invalid on this architecture; needs 68020 or higher";
- }
+ opP->error =
+ "scale factor invalid on this architecture; needs cpu32 or 68020 or higher";
}
switch (opP->index.scale)
else if (siz1 == SIZE_UNSPEC
&& opP->reg == PC
&& isvar (&opP->disp)
- && subs (&opP->disp) == NULL)
+ && subs (&opP->disp) == NULL
+#ifdef OBJ_ELF
+ /* If the displacement needs pic
+ relocation it cannot be relaxed. */
+ && opP->disp.pic_reloc == pic_none
+#endif
+ )
{
+ /* The code in md_convert_frag_1 needs to be
+ able to adjust nextword. Call frag_grow
+ to ensure that we have enough space in
+ the frag obstack to make all the bytes
+ contiguous. */
+ frag_grow (14);
nextword += baseo & 0xff;
addword (nextword);
add_frag (adds (&opP->disp), offs (&opP->disp),
/* Figure out innner displacement stuff */
if (opP->mode == POST || opP->mode == PRE)
{
+ if (cpu_of_arch (current_architecture) & cpu32)
+ opP->error = "invalid operand mode for this architecture; needs 68020 or higher";
switch (siz2)
{
case SIZE_UNSPEC:
if (isvar (&opP->disp)
&& !subs (&opP->disp)
&& adds (&opP->disp)
+#ifdef OBJ_ELF
+ /* If the displacement needs pic relocation it
+ cannot be relaxed. */
+ && opP->disp.pic_reloc == pic_none
+#endif
&& S_GET_SEGMENT (adds (&opP->disp)) == now_seg
&& cpu_of_arch (current_architecture) >= m68020
&& !flag_long_jumps
opP->error = "out of range";
insop (tmpreg, opcode);
if (isvar (&opP->disp))
- the_ins.reloc[the_ins.nrel - 1].n = (opcode->m_codenum) * 2;
+ the_ins.reloc[the_ins.nrel - 1].n =
+ (opcode->m_codenum) * 2 + 1;
+ break;
+ case 'B':
+ if (!issbyte (tmpreg))
+ opP->error = "out of range";
+ opcode->m_opcode |= tmpreg;
+ if (isvar (&opP->disp))
+ the_ins.reloc[the_ins.nrel - 1].n = opcode->m_codenum * 2 - 1;
break;
case 'w':
if (!isword (tmpreg))
if (isvar (&opP->disp))
the_ins.reloc[the_ins.nrel - 1].n = (opcode->m_codenum) * 2;
break;
+ case 'W':
+ if (!issword (tmpreg))
+ opP->error = "out of range";
+ insop (tmpreg, opcode);
+ if (isvar (&opP->disp))
+ the_ins.reloc[the_ins.nrel - 1].n = (opcode->m_codenum) * 2;
+ break;
case 'l':
/* Because of the way insop works, we put these two out
backwards. */
if (subs (&opP->disp)) /* We can't relax it */
goto long_branch;
+#ifdef OBJ_ELF
+ /* If the displacement needs pic relocation it cannot be
+ relaxed. */
+ if (opP->disp.pic_reloc != pic_none)
+ goto long_branch;
+#endif
+
/* This could either be a symbol, or an absolute
address. No matter, the frag hacking will finger it
out. Not quite: it can't switch from BRANCH to
case PCR:
tmpreg = 0x808;
break;
+ case ROMBAR:
+ tmpreg = 0xC00;
+ break;
+ case RAMBAR0:
+ tmpreg = 0xC04;
+ break;
+ case RAMBAR1:
+ tmpreg = 0xC05;
+ break;
+ case MBAR:
+ tmpreg = 0xC0F;
+ break;
default:
abort ();
}
break;
case 'b':
case 'w':
+ case 'W':
case 'l':
break;
case 'e':
{ "ccr", CCR },
{ "cc", CCR },
- { "usp", USP },
- { "isp", ISP },
- { "sfc", SFC },
+ /* control registers */
+ { "sfc", SFC }, /* Source Function Code */
{ "sfcr", SFC },
- { "dfc", DFC },
+ { "dfc", DFC }, /* Destination Function Code */
{ "dfcr", DFC },
- { "cacr", CACR },
- { "caar", CAAR },
-
- { "vbr", VBR },
-
- { "msp", MSP },
- { "itt0", ITT0 },
- { "itt1", ITT1 },
- { "dtt0", DTT0 },
- { "dtt1", DTT1 },
- { "mmusr", MMUSR },
- { "tc", TC },
- { "srp", SRP },
- { "urp", URP },
+ { "cacr", CACR }, /* Cache Control Register */
+ { "caar", CAAR }, /* Cache Address Register */
+
+ { "usp", USP }, /* User Stack Pointer */
+ { "vbr", VBR }, /* Vector Base Register */
+ { "msp", MSP }, /* Master Stack Pointer */
+ { "isp", ISP }, /* Interrupt Stack Pointer */
+
+ { "itt0", ITT0 }, /* Instruction Transparent Translation Reg 0 */
+ { "itt1", ITT1 }, /* Instruction Transparent Translation Reg 1 */
+ { "dtt0", DTT0 }, /* Data Transparent Translation Register 0 */
+ { "dtt1", DTT1 }, /* Data Transparent Translation Register 1 */
+
+ /* 68ec040 versions of same */
+ { "iacr0", ITT0 }, /* Instruction Access Control Register 0 */
+ { "iacr1", ITT1 }, /* Instruction Access Control Register 0 */
+ { "dacr0", DTT0 }, /* Data Access Control Register 0 */
+ { "dacr1", DTT1 }, /* Data Access Control Register 0 */
+
+ /* mcf5200 versions of same. The ColdFire programmer's reference
+ manual indicated that the order is 2,3,0,1, but Ken Rose
+ <rose@netcom.com> says that 0,1,2,3 is the correct order. */
+ { "acr0", ITT0 }, /* Access Control Unit 0 */
+ { "acr1", ITT1 }, /* Access Control Unit 1 */
+ { "acr2", DTT0 }, /* Access Control Unit 2 */
+ { "acr3", DTT1 }, /* Access Control Unit 3 */
+
+ { "tc", TC }, /* MMU Translation Control Register */
+ { "tcr", TC },
+
+ { "mmusr", MMUSR }, /* MMU Status Register */
+ { "srp", SRP }, /* User Root Pointer */
+ { "urp", URP }, /* Supervisor Root Pointer */
+
{ "buscr", BUSCR },
{ "pcr", PCR },
+ { "rombar", ROMBAR }, /* ROM Base Address Register */
+ { "rambar0", RAMBAR0 }, /* ROM Base Address Register */
+ { "rambar1", RAMBAR1 }, /* ROM Base Address Register */
+ { "mbar", MBAR }, /* Module Base Address Register */
+ /* end of control registers */
+
{ "ac", AC },
{ "bc", BC },
{ "cal", CAL },
return;
}
+ /* If there is a current label, record that it marks an instruction. */
+ if (current_label != NULL)
+ {
+ current_label->text = 1;
+ current_label = NULL;
+ }
+
if (the_ins.nfrag == 0)
{
/* No frag hacking involved; just put it out */
n = 1;
break;
case '3':
- n = 2;
+ n = 1;
break;
case 'w':
n = 2;
n,
&the_ins.reloc[m].exp,
the_ins.reloc[m].pcrel,
- NO_RELOC);
+ get_reloc_code (n, the_ins.reloc[m].pcrel,
+ the_ins.reloc[m].pic_reloc));
fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
+ if (the_ins.reloc[m].wid == 'B')
+ fixP->fx_signed = 1;
}
return;
}
wid,
&the_ins.reloc[m].exp,
the_ins.reloc[m].pcrel,
- NO_RELOC);
+ get_reloc_code (wid, the_ins.reloc[m].pcrel,
+ the_ins.reloc[m].pic_reloc));
fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
}
(void) frag_var (rs_machine_dependent, 10, 0,
wid,
&the_ins.reloc[m].exp,
the_ins.reloc[m].pcrel,
- NO_RELOC);
+ get_reloc_code (wid, the_ins.reloc[m].pcrel,
+ the_ins.reloc[m].pic_reloc));
fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
}
}
{
flag_reg_prefix_optional = 1;
m68k_abspcadd = 1;
- m68k_rel32 = 0;
+ if (! m68k_rel32_from_cmdline)
+ m68k_rel32 = 0;
}
op_hash = hash_new ();
*/
alt_notend_table['@'] = 1;
+ /* We need to put digits in alt_notend_table to handle
+ bfextu %d0{24:1},%d0
+ */
+ alt_notend_table['0'] = 1;
+ alt_notend_table['1'] = 1;
+ alt_notend_table['2'] = 1;
+ alt_notend_table['3'] = 1;
+ alt_notend_table['4'] = 1;
+ alt_notend_table['5'] = 1;
+ alt_notend_table['6'] = 1;
+ alt_notend_table['7'] = 1;
+ alt_notend_table['8'] = 1;
+ alt_notend_table['9'] = 1;
+
#ifndef MIT_SYNTAX_ONLY
/* Insert pseudo ops, these have to go into the opcode table since
gas expects pseudo ops to start with a dot */
#endif
init_regtable ();
+
+#ifdef OBJ_ELF
+ record_alignment (text_section, 2);
+ record_alignment (data_section, 2);
+ record_alignment (bss_section, 2);
+#endif
+}
+
+static void
+select_control_regs ()
+{
+ /* Note which set of "movec" control registers is available. */
+ switch (cpu_of_arch (current_architecture))
+ {
+ case m68000:
+ control_regs = m68000_control_regs;
+ break;
+ case m68010:
+ control_regs = m68010_control_regs;
+ break;
+ case m68020:
+ case m68030:
+ control_regs = m68020_control_regs;
+ break;
+ case m68040:
+ control_regs = m68040_control_regs;
+ break;
+ case m68060:
+ control_regs = m68060_control_regs;
+ break;
+ case cpu32:
+ control_regs = cpu32_control_regs;
+ break;
+ case mcf5200:
+ control_regs = mcf5200_control_regs;
+ break;
+ default:
+ abort ();
+ }
}
void
#endif
/* Note which set of "movec" control registers is available. */
- switch (cpu_of_arch (current_architecture))
- {
- case m68000:
- control_regs = m68000_control_regs;
- break;
- case m68010:
- control_regs = m68010_control_regs;
- break;
- case m68020:
- case m68030:
- control_regs = m68020_control_regs;
- break;
- case m68040:
- control_regs = m68040_control_regs;
- break;
- case m68060:
- control_regs = m68060_control_regs;
- break;
- case cpu32:
- control_regs = cpu32_control_regs;
- break;
- default:
- abort ();
- }
+ select_control_regs ();
if (cpu_of_arch (current_architecture) < m68020)
md_relax_table[TAB (PCINDEX, BYTE)].rlx_more = 0;
}
+\f
+/* This is called when a label is defined. */
+
+void
+m68k_frob_label (sym)
+ symbolS *sym;
+{
+ struct label_line *n;
+
+ n = (struct label_line *) xmalloc (sizeof *n);
+ n->next = labels;
+ n->label = sym;
+ as_where (&n->file, &n->line);
+ labels = n;
+ current_label = n;
+}
+
+/* This is called when a value that is not an instruction is emitted. */
+
+void
+m68k_flush_pending_output ()
+{
+ current_label = NULL;
+}
+
+/* This is called at the end of the assembly, when the final value of
+ the label is known. We warn if this is a text symbol aligned at an
+ odd location. */
+
+void
+m68k_frob_symbol (sym)
+ symbolS *sym;
+{
+ if ((S_GET_VALUE (sym) & 1) != 0)
+ {
+ struct label_line *l;
+
+ for (l = labels; l != NULL; l = l->next)
+ {
+ if (l->label == sym)
+ {
+ if (l->text)
+ as_warn_where (l->file, l->line,
+ "text label `%s' aligned to odd boundary",
+ S_GET_NAME (sym));
+ break;
+ }
+ }
+ }
+}
+\f
+/* This is called if we go in or out of MRI mode because of the .mri
+ pseudo-op. */
+
+void
+m68k_mri_mode_change (on)
+ int on;
+{
+ if (on)
+ {
+ if (! flag_reg_prefix_optional)
+ {
+ flag_reg_prefix_optional = 1;
+#ifdef REGISTER_PREFIX
+ init_regtable ();
+#endif
+ }
+ m68k_abspcadd = 1;
+ if (! m68k_rel32_from_cmdline)
+ m68k_rel32 = 0;
+ }
+ else
+ {
+ if (! reg_prefix_optional_seen)
+ {
+#ifdef REGISTER_PREFIX_OPTIONAL
+ flag_reg_prefix_optional = REGISTER_PREFIX_OPTIONAL;
+#else
+ flag_reg_prefix_optional = 0;
+#endif
+#ifdef REGISTER_PREFIX
+ init_regtable ();
+#endif
+ }
+ m68k_abspcadd = 0;
+ if (! m68k_rel32_from_cmdline)
+ m68k_rel32 = 1;
+ }
+}
/* Equal to MAX_PRECISION in atof-ieee.c */
#define MAX_LITTLENUMS 6
else
val &= 0x7fffffff;
+#ifdef OBJ_ELF
+ if (fixP->fx_addsy)
+ {
+ memset (buf, 0, fixP->fx_size);
+ fixP->fx_addnumber = val; /* Remember value for emit_reloc */
+ return;
+ }
+#endif
+
switch (fixP->fx_size)
{
/* The cast to offsetT below are necessary to make code correct for
like "0xff" for a byte field. So extend the upper part of the range
to accept such numbers. We arbitrarily disallow "-0xff" or "0xff+0xff",
so that we can do any range checking at all. */
- if (!fixP->fx_pcrel)
+ if (! fixP->fx_pcrel && ! fixP->fx_signed)
upper_limit = upper_limit * 2 + 1;
if ((addressT) val > upper_limit
{
case TAB (BCC68000, BYTE):
case TAB (ABRANCH, BYTE):
- /* We can't do a short jump to the next instruction,
- so we force word mode. */
- if (fragP->fr_symbol && S_GET_VALUE (fragP->fr_symbol) == 0 &&
- fragP->fr_symbol->sy_frag == fragP->fr_next)
+ /* We can't do a short jump to the next instruction, so in that
+ case we force word mode. At this point S_GET_VALUE should
+ return the offset of the symbol within its frag. If the
+ symbol is at the start of a frag, and it is the next frag
+ with any data in it (usually this is just the next frag, but
+ assembler listings may introduce empty frags), we must use
+ word mode. */
+ if (fragP->fr_symbol && S_GET_VALUE (fragP->fr_symbol) == 0)
{
- fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
- fragP->fr_var += 2;
+ fragS *l;
+
+ for (l = fragP->fr_next;
+ l != fragP->fr_symbol->sy_frag;
+ l = l->fr_next)
+ if (l->fr_fix + l->fr_var != 0)
+ break;
+ if (l == fragP->fr_symbol->sy_frag)
+ {
+ fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
+ fragP->fr_var += 2;
+ }
}
break;
default:
if (!need_pass_2) /* Never make frag if expect extra pass. */
frag_align (temp, (int) temp_fill);
demand_empty_rest_of_line ();
+ record_alignment (now_seg, temp);
}
static void
\f
/* Pseudo-ops handled for MRI compatibility. */
+/* This function returns non-zero if the argument is a conditional
+ pseudo-op. This is called when checking whether a pending
+ alignment is needed. */
+
+int
+m68k_conditional_pseudoop (pop)
+ pseudo_typeS *pop;
+{
+ return (pop->poc_handler == s_mri_if
+ || pop->poc_handler == s_mri_else);
+}
+
/* Handle an MRI style chip specification. */
static void
current_architecture |= m68851;
*input_line_pointer = c;
}
+
+ /* Update info about available control registers. */
+ select_control_regs ();
}
/* The MRI CHIP pseudo-op. */
input_line_pointer = s;
+ pop_mri_control ();
+
if (flag_mri)
{
while (! is_end_of_line[(unsigned char) *input_line_pointer])
* -pic Indicates PIC.
* -k Indicates PIC. (Sun 3 only.)
*
+ * --bitwise-or
+ * Permit `|' to be used in expressions.
+ *
*/
#ifdef OBJ_ELF
#define OPTION_REGISTER_PREFIX_OPTIONAL (OPTION_MD_BASE + 1)
{"register-prefix-optional", no_argument, NULL,
OPTION_REGISTER_PREFIX_OPTIONAL},
+#define OPTION_BITWISE_OR (OPTION_MD_BASE + 2)
+ {"bitwise-or", no_argument, NULL, OPTION_BITWISE_OR},
+#define OPTION_BASE_SIZE_DEFAULT_16 (OPTION_MD_BASE + 3)
+ {"base-size-default-16", no_argument, NULL, OPTION_BASE_SIZE_DEFAULT_16},
+#define OPTION_BASE_SIZE_DEFAULT_32 (OPTION_MD_BASE + 4)
+ {"base-size-default-32", no_argument, NULL, OPTION_BASE_SIZE_DEFAULT_32},
+#define OPTION_DISP_SIZE_DEFAULT_16 (OPTION_MD_BASE + 5)
+ {"disp-size-default-16", no_argument, NULL, OPTION_DISP_SIZE_DEFAULT_16},
+#define OPTION_DISP_SIZE_DEFAULT_32 (OPTION_MD_BASE + 6)
+ {"disp-size-default-32", no_argument, NULL, OPTION_DISP_SIZE_DEFAULT_32},
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof(md_longopts);
case OPTION_REGISTER_PREFIX_OPTIONAL:
flag_reg_prefix_optional = 1;
+ reg_prefix_optional_seen = 1;
break;
- case 'Q':
+ /* -V: SVR4 argument to print version ID. */
case 'V':
+ print_version_id ();
+ break;
+
+ /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section
+ should be emitted or not. FIXME: Not implemented. */
+ case 'Q':
+ break;
+
+ case OPTION_BITWISE_OR:
+ {
+ char *n, *t;
+ const char *s;
+
+ n = (char *) xmalloc (strlen (m68k_comment_chars) + 1);
+ t = n;
+ for (s = m68k_comment_chars; *s != '\0'; s++)
+ if (*s != '|')
+ *t++ = *s;
+ *t = '\0';
+ m68k_comment_chars = n;
+ }
+ break;
+
+ case OPTION_BASE_SIZE_DEFAULT_16:
+ m68k_index_width_default = SIZE_WORD;
+ break;
+
+ case OPTION_BASE_SIZE_DEFAULT_32:
+ m68k_index_width_default = SIZE_LONG;
+ break;
+
+ case OPTION_DISP_SIZE_DEFAULT_16:
+ m68k_rel32 = 0;
+ m68k_rel32_from_cmdline = 1;
+ break;
+
+ case OPTION_DISP_SIZE_DEFAULT_32:
+ m68k_rel32 = 1;
+ m68k_rel32_from_cmdline = 1;
break;
default:
-l use 1 word for refs to undefined symbols [default 2]\n\
-m68000 | -m68008 | -m68010 | -m68020 | -m68030 | -m68040 | -m68060\n\
| -m68302 | -m68331 | -m68332 | -m68333 | -m68340 | -m68360\n\
- | -mcpu32\n\
+ | -mcpu32 | -m5200\n\
specify variant of 680X0 architecture [default 68020]\n\
-m68881 | -m68882 | -mno-68881 | -mno-68882\n\
target has/lacks floating-point coprocessor\n\
-pic, -k generate position independent code\n\
-S turn jbsr into jsr\n\
--register-prefix-optional\n\
- recognize register names without prefix character\n");
+ recognize register names without prefix character\n\
+--bitwise-or do not treat `|' as a comment character\n");
+ fprintf (stream, "\
+--base-size-default-16 base reg without size is 16 bits\n\
+--base-size-default-32 base reg without size is 32 bits (default)\n\
+--disp-size-default-16 displacement with unknown size is 16 bits\n\
+--disp-size-default-32 displacement with unknown size is 32 bits (default)\n");
}
\f
#ifdef TEST2