/* tc-mips.c -- assemble code for a MIPS chip.
- Copyright (C) 1993, 94, 95, 96, 97, 98, 1999, 2000
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
Contributed by the OSF and Ralph Campbell.
Written by Keith Knowles and Ralph Campbell, working independently.
#ifdef TE_TMIPS
/* This is traditional mips */
return (target_big_endian
- ? "elf32-tradbigmips" : "elf32-tradlittlemips");
+ ? (mips_64 ? "elf64-tradbigmips" : "elf32-tradbigmips")
+ : (mips_64 ? "elf64-tradlittlemips" : "elf32-tradlittlemips"));
#else
return (target_big_endian
? (mips_64 ? "elf64-bigmips" : "elf32-bigmips")
pseudo-op. We use a struct so that .set push and .set pop are more
reliable. */
-struct mips_set_options {
+struct mips_set_options
+{
/* MIPS ISA (Instruction Set Architecture) level. This is set to -1
if it has not been initialized. Changed by `.set mipsN', and the
-mipsN command line option, and the default CPU. */
that we must set the isa field to ISA_UNKNOWN and the mips16 field to
-1 to indicate that they have not been initialized. */
-static struct mips_set_options mips_opts = {
+static struct mips_set_options mips_opts =
+{
ISA_UNKNOWN, -1, 0, 0, 0, 0, 0, 0
};
static int mips_cpu = CPU_UNKNOWN;
/* The argument of the -mabi= flag. */
-static char *mips_abi_string = 0;
+static char * mips_abi_string = 0;
/* Wether we should mark the file EABI64 or EABI32. */
static int mips_eabi64 = 0;
/* MIPS PIC level. */
-enum mips_pic_level {
+enum mips_pic_level
+{
/* Do not generate PIC code. */
NO_PIC,
relocation. We then sort them so that they immediately precede the
corresponding LO relocation. */
-struct mips_hi_fixup {
+struct mips_hi_fixup
+{
/* Next HI fixup. */
struct mips_hi_fixup *next;
/* This fixup. */
/* Map normal MIPS register numbers to mips16 register numbers. */
#define X ILLEGAL_REG
-static const int mips32_to_16_reg_map[] = {
+static const int mips32_to_16_reg_map[] =
+{
X, X, 2, 3, 4, 5, 6, 7,
X, X, X, X, X, X, X, X,
0, 1, X, X, X, X, X, X,
/* Map mips16 register numbers to normal MIPS register numbers. */
-static const unsigned int mips16_to_32_reg_map[] = {
+static const unsigned int mips16_to_32_reg_map[] =
+{
16, 17, 2, 3, 4, 5, 6, 7
};
\f
/* Table and functions used to map between CPU/ISA names, and
ISA levels, and CPU numbers. */
-struct mips_cpu_info {
+struct mips_cpu_info
+{
const char *name; /* CPU or ISA name. */
int is_isa; /* Is this an ISA? (If 0, a CPU.) */
int isa; /* ISA level. */
they are not currently supported: .asm0, .endr, .lab, .repeat,
.struct. */
-static const pseudo_typeS mips_pseudo_table[] = {
+static const pseudo_typeS mips_pseudo_table[] =
+{
/* MIPS specific pseudo-ops. */
{"option", s_option, 0},
{"set", s_mipsset, 0},
{ NULL, NULL, 0 },
};
-static const pseudo_typeS mips_nonecoff_pseudo_table[] = {
+static const pseudo_typeS mips_nonecoff_pseudo_table[] =
+{
/* These pseudo-ops should be defined by the object file format.
However, a.out doesn't support them, so we have versions here. */
{"aent", s_mips_ent, 1},
\f
/* Symbols labelling the current insn. */
-struct insn_label_list {
+struct insn_label_list
+{
struct insn_label_list *next;
symbolS *label;
};
&& insn_uses_reg (ip, ((prev_insn.insn_opcode >> OP_SH_RD)
& OP_MASK_RD),
MIPS_GR_REG))
-
{
nops += 2;
}
if (mips_trap)
macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", 0, 0);
else
- macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+ macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
return;
}
macro_build ((char *) NULL, &icnt, NULL,
dbl ? "ddiv" : "div",
"z,s,t", sreg, treg);
- macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+ macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
}
expr1.X_add_number = -1;
macro_build ((char *) NULL, &icnt, &expr1,
that later insns are available for delay slot filling. */
--mips_opts.noreorder;
- macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
+ macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
}
macro_build ((char *) NULL, &icnt, NULL, s, "d", dreg);
break;
}
else if (mips_pic == SVR4_PIC && ! mips_big_got)
{
+ int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
+
/* If this is a reference to an external symbol, and there
is no constant, we want
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
+ or if tempreg is PIC_CALL_REG
+ lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_CALL16)
For a local symbol, we want
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
nop
expr1.X_add_number = offset_expr.X_add_number;
offset_expr.X_add_number = 0;
frag_grow (32);
+ if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG)
+ lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16;
macro_build ((char *) NULL, &icnt, &offset_expr,
dbl ? "ld" : "lw",
- "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
+ "t,o(b)", tempreg, lw_reloc_type, GP);
if (expr1.X_add_number == 0)
{
int off;
else if (mips_pic == SVR4_PIC)
{
int gpdel;
+ int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
+ int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
/* This is the large GOT case. If this is a reference to an
external symbol, and there is no constant, we want
lui $tempreg,<sym> (BFD_RELOC_MIPS_GOT_HI16)
addu $tempreg,$tempreg,$gp
lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
+ or if tempreg is PIC_CALL_REG
+ lui $tempreg,<sym> (BFD_RELOC_MIPS_CALL_HI16)
+ addu $tempreg,$tempreg,$gp
+ lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_CALL_LO16)
For a local symbol, we want
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
nop
gpdel = 4;
else
gpdel = 0;
+ if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG)
+ {
+ lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
+ lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
+ }
macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
- tempreg, (int) BFD_RELOC_MIPS_GOT_HI16);
+ tempreg, lui_reloc_type);
macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
((bfd_arch_bits_per_address (stdoutput) == 32
|| ! ISA_HAS_64BIT_REGS (mips_opts.isa))
"d,v,t", tempreg, tempreg, GP);
macro_build ((char *) NULL, &icnt, &offset_expr,
dbl ? "ld" : "lw",
- "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT_LO16,
- tempreg);
+ "t,o(b)", tempreg, lw_reloc_type, tempreg);
if (expr1.X_add_number == 0)
{
int off;
case 'G': USE_BITS (OP_MASK_RD, OP_SH_RD); break;
case 'H': USE_BITS (OP_MASK_SEL, OP_SH_SEL); break;
case 'I': break;
- case 'J': USE_BITS (OP_MASK_CODE19, OP_SH_CODE19); break;
+ case 'J': USE_BITS (OP_MASK_CODE19, OP_SH_CODE19); break;
case 'L': break;
case 'M': USE_BITS (OP_MASK_CCC, OP_SH_CCC); break;
case 'N': USE_BITS (OP_MASK_BCC, OP_SH_BCC); break;
/* This structure holds information we know about a mips16 immediate
argument type. */
-struct mips16_immed_operand {
+struct mips16_immed_operand
+{
/* The type code used in the argument string in the opcode table. */
int type;
/* The number of bits in the short form of the opcode. */
\f
CONST char *md_shortopts = "O::g::G:";
-struct option md_longopts[] = {
+struct option md_longopts[] =
+{
#define OPTION_MIPS1 (OPTION_MD_BASE + 1)
{"mips0", no_argument, NULL, OPTION_MIPS1},
{"mips1", no_argument, NULL, OPTION_MIPS1},
g_switch_value = 0x7fffffff;
break;
+#ifdef OBJ_ELF
/* When generating ELF code, we permit -KPIC and -call_shared to
select SVR4_PIC, and -non_shared to select no PIC. This is
intended to be compatible with Irix 5. */
case OPTION_XGOT:
mips_big_got = 1;
break;
+#endif /* OBJ_ELF */
case 'G':
if (! USE_GLOBAL_POINTER_OPT)
g_switch_seen = 1;
break;
+#ifdef OBJ_ELF
/* The -32 and -64 options tell the assembler to output the 32
bit or the 64 bit MIPS ELF format. */
case OPTION_32:
mips_64 = 1;
}
break;
+#endif /* OBJ_ELF */
case OPTION_GP32:
mips_gp32 = 1;
/* This structure is used to hold a stack of .set values. */
-struct mips_option_stack {
+struct mips_option_stack
+{
struct mips_option_stack *next;
struct mips_set_options options;
};
ext = false;
}
- resolve_symbol_value (fragp->fr_symbol, 1);
+ resolve_symbol_value (fragp->fr_symbol, finalize_syms);
val = S_GET_VALUE (fragp->fr_symbol);
if (op->pcrel)
{
static procS *cur_proc_ptr;
static int numprocs;
-/* When we align code in the .text section of mips16, use the correct two
- byte nop pattern of 0x6500 (move $0,$0) */
+/* Fill in an rs_align_code fragment. */
-int
-mips_do_align (n, fill, len, max)
- int n;
- const char *fill;
- int len ATTRIBUTE_UNUSED;
- int max;
+void
+mips_handle_align (fragp)
+ fragS *fragp;
{
- if (fill == NULL
- && subseg_text_p (now_seg)
- && n > 1
- && mips_opts.mips16)
+ if (fragp->fr_type != rs_align_code)
+ return;
+
+ if (mips_opts.mips16)
{
static const unsigned char be_nop[] = { 0x65, 0x00 };
static const unsigned char le_nop[] = { 0x00, 0x65 };
- frag_align (1, 0, 0);
+ int bytes;
+ char *p;
- if (target_big_endian)
- frag_align_pattern (n, be_nop, 2, max);
- else
- frag_align_pattern (n, le_nop, 2, max);
- return 1;
+ bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
+ p = fragp->fr_literal + fragp->fr_fix;
+
+ if (bytes & 1)
+ {
+ *p++ = 0;
+ fragp->fr_fix += 1;
+ }
+
+ memcpy (p, (target_big_endian ? be_nop : le_nop), 2);
+ fragp->fr_var = 2;
}
- return 0;
+ /* For mips32, a nop is a zero, which we trivially get by doing nothing. */
}
static void
Case is ignored in comparison, so put the canonical entry in the
appropriate case but everything else in lower case to ease eye pain. */
-static const struct mips_cpu_info mips_cpu_info_table[] = {
+static const struct mips_cpu_info mips_cpu_info_table[] =
+{
/* MIPS1 ISA */
{ "MIPS1", 1, ISA_MIPS1, CPU_R3000, },
{ "mips", 1, ISA_MIPS1, CPU_R3000, },
/* TX3900 CPU */
{ "R3900", 0, ISA_MIPS1, CPU_R3900, },
{ "3900", 0, ISA_MIPS1, CPU_R3900, },
- { "mipstx39", 0, ISA_MIPS1, CPU_R3900, },
+ { "mipstx39", 0, ISA_MIPS1, CPU_R3900, },
/* R4000 CPU */
{ "R4000", 0, ISA_MIPS3, CPU_R4000, },
/* SiByte SB-1 CPU */
{ "SB-1", 0, ISA_MIPS64, CPU_SB1, },
- { "sb-1250", 0, ISA_MIPS64, CPU_SB1, },
+ { "sb-1250", 0, ISA_MIPS64, CPU_SB1, },
{ "sb1", 0, ISA_MIPS64, CPU_SB1, },
{ "sb1250", 0, ISA_MIPS64, CPU_SB1, },
if (strcasecmp (name, mips_cpu_info_table[i].name) == 0)
return (&mips_cpu_info_table[i]);
- return (NULL);
+ return NULL;
}
static const struct mips_cpu_info *
&& isa == mips_cpu_info_table[i].isa)
return (&mips_cpu_info_table[i]);
- return (NULL);
+ return NULL;
}
static const struct mips_cpu_info *
&& cpu == mips_cpu_info_table[i].cpu)
return (&mips_cpu_info_table[i]);
- return (NULL);
+ return NULL;
}