This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [PATCH 1/2] Add support for O32 FPXX ABI
- From: Doug Gilmore <Doug dot Gilmore at imgtec dot com>
- To: Matthew Fortune <Matthew dot Fortune at imgtec dot com>, Richard Sandiford <rdsandiford at googlemail dot com>
- Cc: "macro at codesourcery dot com" <macro at codesourcery dot com>, "Joseph Myers (joseph at codesourcery dot com)" <joseph at codesourcery dot com>, "binutils at sourceware dot org" <binutils at sourceware dot org>, Rich Fuhler <Rich dot Fuhler at imgtec dot com>
- Date: Fri, 2 May 2014 13:30:58 -0700
- Subject: Re: [PATCH 1/2] Add support for O32 FPXX ABI
- Authentication-results: sourceware.org; auth=none
- References: <6D39441BF12EF246A7ABCE6654B023534DAAAB at LEMAIL01 dot le dot imgtec dot org> <6D39441BF12EF246A7ABCE6654B023534DFD9B at LEMAIL01 dot le dot imgtec dot org> <87fvll1ha9 dot fsf at sandifor-thinkpad dot stglab dot manchester dot uk dot ibm dot com> <6D39441BF12EF246A7ABCE6654B023534E07CB at LEMAIL01 dot le dot imgtec dot org> <87k3awnuf1 dot fsf at talisman dot default> <6D39441BF12EF246A7ABCE6654B023534E0F50 at LEMAIL01 dot le dot imgtec dot org> <87ppknzv7m dot fsf at talisman dot default> <6D39441BF12EF246A7ABCE6654B023534E16D7 at LEMAIL01 dot le dot imgtec dot org> <877g6vzpj1 dot fsf at talisman dot default> <6D39441BF12EF246A7ABCE6654B023534E3030 at LEMAIL01 dot le dot imgtec dot org> <87eh0yl4xx dot fsf at talisman dot default> <6D39441BF12EF246A7ABCE6654B023534E3AA8 at LEMAIL01 dot le dot imgtec dot org> <87d2ghk7fu dot fsf at talisman dot default> <6D39441BF12EF246A7ABCE6654B023535127C8 at LEMAIL01 dot le dot imgtec dot org> <87r44mve6s dot fsf at sandifor-thinkpad dot stglab dot manchester dot uk dot ibm dot com> <6D39441BF12EF246A7ABCE6654B02353512A10 at LEMAIL01 dot le dot imgtec dot org> <87r44leu34 dot fsf at talisman dot default> <6D39441BF12EF246A7ABCE6654B0235351D76A at LEMAIL01 dot le dot imgtec dot org>
On 05/01/2014 07:42 AM, Matthew Fortune wrote:
> Hi Richard,
>
> Updated patch below. The changes are:
>
> * Update structure to add cpr1_size and cpr2_size.
> * When merging object's private data take the maximum of register sizes
>
> The spec for O32 FPXX has been updated to account for all recent changes.
> https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking
>
> regards,
> Matthew
>
Hi Matthew,
I had problems applying your patch, so I attached a copy that I could apply
cleanly.
Doug
>From 1fee5487105e4c72d94a64b514deb02e6d0bc593 Mon Sep 17 00:00:00 2001
From: mfortune <matthew.fortune@imgtec.com>
Date: Sat, 29 Mar 2014 11:40:50 +0000
Subject: [PATCH] Add support for O32 FPXX ABI
include/
* elf/mips.h (PT_MIPS_ABIFLAGS, SHT_MIPS_ABIFLAGS): Define.
(Val_GNU_MIPS_ABI_FP_OLD_64): Rename from Val_GNU_MIPS_ABI_FP_64.
(Val_GNU_MIPS_ABI_FP_64): Redefine.
(Val_GNU_MIPS_ABI_FP_XX): Define.
(Elf_External_ABIFlags_v0, Elf_Internal_ABIFlags_v0): New structures.
(AFL_REG_NONE, AFL_REG_32, AFL_REG_64, AFL_REG_128): Define.
(AFL_ASE_*): Define. Moved and renamed from opcode/mips.h ASE_*.
(AFL_EXT_*): Define. Moved and renamed from opcode/mips.h INSN_*.
* opcode/mips.h (elf/mips.h): Include.
(INSN_*, ASE_*): Remove.
(cpu_insn_mask): New static inline function. Derived from cpu_is_member.
(cpu_is_member): Rework to use cpu_insn_mask.
bfd/
* elfxx-mips.c (ABI_O32_P, MIPS_ELF_ABIFLAGS_SECTION_NAME_P): New macro.
(_bfd_mips_elf_additional_program_headers): Account for new
PT_MIPS_ABIFLAGS program header.
(_bfd_mips_elf_modify_segment_map): Create PT_MIPS_ABIFLAGS segment and
associate with .MIPS.abiflags.
(mips_elf_merge_obj_attributes): Error checking for
Val_GNU_MIPS_ABI_FP_OLD_64 and Val_GNU_MIPS_ABI_FP_XX.
Check EF_MIPS_FP64 flag consistency.
(_bfd_mips_elf_merge_private_bfd_data): Restructure and add abiflags checks.
(_bfd_mips_elf_print_private_bfd_data): Display abiflags data.
(mips_elf_obj_tdata): Add abiflags and abiflags_valid fields.
(bfd_mips_elf_swap_abiflags_v0_in, bfd_mips_elf_swap_abiflags_v0_out):
New function.
(_bfd_mips_elf_section_from_shdr, _bfd_mips_elf_fake_sections): Handle
SHT_MIPS_ABIFLAGS.
(_bfd_mips_elf_always_size_sections): Handle .MIPS.abiflags.
(update_mips_abiflags_isa, infer_mips_abiflags, print_mips_ases,
print_mips_isa_ext, print_mips_fp_abi_value, get_mips_reg_size): New
static functions.
(mips_32bit_flags_p): Moved higher.
(_bfd_mips_elf_final_link): Handle .MIPS.abiflags
binutils/
* readelf.c (get_mips_segment_type): Display name for PT_MIPS_ABIFLAGS.
(get_mips_section_type_name): Display name for SHT_MIPS_ABIFLAGS.
(display_mips_gnu_attribute): Abstracted fp abi printing to...
(print_mips_fp_abi_value): New static function. Handle
Val_GNU_MIPS_ABI_FP_OLD_64 and Val_GNU_MIPS_ABI_FP_XX.
(print_mips_ases, print_mips_isa_ext, get_mips_reg_size): New static
functions.
(process_mips_specific): Display abiflags data.
elfcpp/
* elfcpp.h (PT_MIPS_ABIFLAGS): New program header type.
gas/
* config/tc-mips.c (struct mips_set_options): Rename fp32 to fp to allow
it to store three modes 32, 0==FPXX, 64, update all occurences. Add
mips_defer_fp_warn.
(mips_seen_fp_code, file_mips_opts_checked, mips_flags_frag): New static
global.
(file_mips_opts): New static global replacing...
(file_mips_gp32, file_mips_fp32, file_mips_isa, file_mips_arch,
file_mips_soft_float, file_mips_single_float): Delete global.
(mips_opts): Update defaults due to structure changes.
(md_parse_option): Update due to change in globals.
(s_module): New static function.
(enum options, md_longopts, md_parse_option): Add -mfpxx option.
(mips_pseudo_table): Add .module handler.
(mips_set_ase): Add opts argument and use instead of mips_opts.
(md_begin): Use file_mips_opts instead of file_mips_*. Create .MIPS.abiflags
section.
(md_mips_end): Add consistency checks for command line, .module and
.gnu_attribute. Update .gnu_attribute based on command line and .module
as applicable.
(md_assemble): Use file_mips_check_options.
(check_regno): Set mips_seen_fp_code. Handle mips_defer_fp_warn.
(match_float_constant): Rewrite check regarding FP register width. Add
support for generating constants when MXHC1 is present. Handle fp==0 to
comply with FPXX ABI.
(macro): Update M_LI_DD similarly to match_float_constant. Generate MTHC1
when available. Check that correct code can be generated for FPXX and
FP64 ABIs.
(mips_set_architecture): Delete function. Moved to mips_after_parse_args.
(mips_after_parse_args): Move error checking to mips_check_options. All
logic now applies to file_mips_opts first and then copies the final state
to mips_opts.
(mips_check_options): New static function. Common option checking for
command line, .module and .set. Use general terms in error messages
instead of refering to command line options.
(file_mips_check_options): New static function. A wrapper for
mips_check_options with file_mips_opts.
(s_mipsset): Split into s_mipsset and s_mipssettings. Settings supported
by both .set and .module are moved to s_mipssettings. Warnings and errors
are kept in s_mipsset because when s_mipssettings is used with s_module
the warnings are deferred until code is generated. Any setting supporting
'default' value is kept in s_mipsset as it is not applicable to s_module.
Inferred settings are also kept in s_mipsset as s_module does not infer
any settings. Use mips_check_options. Set mips_defer_fp_warn.
(s_mipssettings): New static function derived from s_mipsset.
(s_module): New static function that implements .module. Allows file
level settings to be changed until code is generated. Updates BFD arch
if it is changed by .module.
(s_cpload, s_cpsetup, s_cplocal, s_cprestore, s_cpreturn, s_cpadd): Use
file_mips_check_options.
(mips_elf_final_processing): Use fpabi == Val_GNU_MIPS_ABI_FP_OLD_64
to determine when to add the EF_MIPS_FP64 flag. Populate the .MIPS.abiflags
section.
(md_obj_end): Use file_mips_check_options.
(mips_parse_cpu): Update for globals.
(mips_convert_symbolic_attribute): Support names for .gnu_attribute.
(ASE_*): Rename throughout to AFL_ASE_*.
(INSN_*): Rename throughout to AFL_EXT_*.
* config/tc-mips.h (CONVERT_SYMBOLIC_ATTRIBUTE): Implement macro.
* doc/c-mips.texi: Document -mfpxx, gnu_attribute values and FP ABIs.
ld/
* emulparams/elf32bmip.sh: Add .MIPS.abiflags_valid.
* emulparams/elf32bmipn32-defs.sh: Add .MIPS.abiflags_valid.
opcodes/
* micromips-opc.c (ASE_*): Rename throughout to AFL_ASE_*.
* mips-dis.c (ASE_*): Rename throughout to AFL_ASE_*.
(INSN_*): Rename throughout to AFL_EXT_*.
* mips-opc.c (ASE_*): Rename throughout to AFL_ASE_*.
(INSN_*): Rename throughout to AFL_EXT_*.
---
bfd/elfxx-mips.c | 728 ++++++++++++++++++++++++--
binutils/readelf.c | 204 +++++++-
elfcpp/elfcpp.h | 4 +-
gas/config/tc-mips.c | 1012 +++++++++++++++++++++++-------------
gas/config/tc-mips.h | 5 +
gas/doc/as.texinfo | 14 +
gas/doc/c-mips.texi | 128 +++++
include/elf/mips.h | 118 ++++-
include/opcode/mips.h | 116 +----
ld/emulparams/elf32bmip.sh | 3 +-
ld/emulparams/elf32bmipn32-defs.sh | 1 +
opcodes/micromips-opc.c | 18 +-
opcodes/mips-dis.c | 44 +-
opcodes/mips-opc.c | 68 +--
14 files changed, 1895 insertions(+), 568 deletions(-)
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index d939444..0a15d1a 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -547,6 +547,10 @@ struct mips_elf_obj_tdata
/* Input BFD providing Tag_GNU_MIPS_ABI_MSA attribute for output. */
bfd *abi_msa_bfd;
+ /* The abiflags for this object. */
+ Elf_Internal_ABIFlags_v0 abiflags;
+ bfd_boolean abiflags_valid;
+
/* The GOT requirements of input bfds. */
struct mips_got_info *got;
@@ -776,6 +780,10 @@ static bfd *reldyn_sorting_bfd;
#define PIC_OBJECT_P(abfd) \
((elf_elfheader (abfd)->e_flags & EF_MIPS_PIC) != 0)
+/* Nonzero if ABFD is using the O32 ABI. */
+#define ABI_O32_P(abfd) \
+ ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI) == E_MIPS_ABI_O32)
+
/* Nonzero if ABFD is using the N32 ABI. */
#define ABI_N32_P(abfd) \
((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0)
@@ -808,6 +816,10 @@ static bfd *reldyn_sorting_bfd;
#define MIPS_ELF_OPTIONS_SECTION_NAME_P(NAME) \
(strcmp (NAME, ".MIPS.options") == 0 || strcmp (NAME, ".options") == 0)
+/* True if NAME is the recognized name of any SHT_MIPS_ABIFLAGS section. */
+#define MIPS_ELF_ABIFLAGS_SECTION_NAME_P(NAME) \
+ (strcmp (NAME, ".MIPS.abiflags") == 0)
+
/* Whether the section is readonly. */
#define MIPS_ELF_READONLY_SECTION(sec) \
((sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY)) \
@@ -2664,6 +2676,46 @@ bfd_mips_elf_swap_options_out (bfd *abfd, const Elf_Internal_Options *in,
H_PUT_16 (abfd, in->section, ex->section);
H_PUT_32 (abfd, in->info, ex->info);
}
+
+/* Swap in an abiflags structure. */
+
+void
+bfd_mips_elf_swap_abiflags_v0_in (bfd *abfd,
+ const Elf_External_ABIFlags_v0 *ex,
+ Elf_Internal_ABIFlags_v0 *in)
+{
+ in->version = H_GET_16 (abfd, ex->version);
+ in->isa_level = H_GET_8 (abfd, ex->isa_level);
+ in->isa_rev = H_GET_8 (abfd, ex->isa_rev);
+ in->gpr_size = H_GET_8 (abfd, ex->gpr_size);
+ in->cpr1_size = H_GET_8 (abfd, ex->cpr1_size);
+ in->cpr2_size = H_GET_8 (abfd, ex->cpr2_size);
+ in->fp_abi = H_GET_8 (abfd, ex->fp_abi);
+ in->isa_ext = H_GET_32 (abfd, ex->isa_ext);
+ in->ases = H_GET_32 (abfd, ex->ases);
+ in->flags1 = H_GET_32 (abfd, ex->flags1);
+ in->flags2 = H_GET_32 (abfd, ex->flags2);
+}
+
+/* Swap out an abiflags structure. */
+
+void
+bfd_mips_elf_swap_abiflags_v0_out (bfd *abfd,
+ const Elf_Internal_ABIFlags_v0 *in,
+ Elf_External_ABIFlags_v0 *ex)
+{
+ H_PUT_16 (abfd, in->version, ex->version);
+ H_PUT_8 (abfd, in->isa_level, ex->isa_level);
+ H_PUT_8 (abfd, in->isa_rev, ex->isa_rev);
+ H_PUT_8 (abfd, in->gpr_size, ex->gpr_size);
+ H_PUT_8 (abfd, in->cpr1_size, ex->cpr1_size);
+ H_PUT_8 (abfd, in->cpr2_size, ex->cpr2_size);
+ H_PUT_8 (abfd, in->fp_abi, ex->fp_abi);
+ H_PUT_32 (abfd, in->isa_ext, ex->isa_ext);
+ H_PUT_32 (abfd, in->ases, ex->ases);
+ H_PUT_32 (abfd, in->flags1, ex->flags1);
+ H_PUT_32 (abfd, in->flags2, ex->flags2);
+}
/* This function is called via qsort() to sort the dynamic relocation
entries by increasing r_symndx value. */
@@ -6910,6 +6962,11 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
if (!MIPS_ELF_OPTIONS_SECTION_NAME_P (name))
return FALSE;
break;
+ case SHT_MIPS_ABIFLAGS:
+ if (!MIPS_ELF_ABIFLAGS_SECTION_NAME_P (name))
+ return FALSE;
+ flags = (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_SAME_SIZE);
+ break;
case SHT_MIPS_DWARF:
if (! CONST_STRNEQ (name, ".debug_")
&& ! CONST_STRNEQ (name, ".zdebug_"))
@@ -6940,6 +6997,20 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
return FALSE;
}
+ if (hdr->sh_type == SHT_MIPS_ABIFLAGS)
+ {
+ Elf_External_ABIFlags_v0 ext;
+
+ if (! bfd_get_section_contents (abfd, hdr->bfd_section,
+ &ext, 0, sizeof ext))
+ return FALSE;
+ bfd_mips_elf_swap_abiflags_v0_in (abfd, &ext,
+ &mips_elf_tdata (abfd)->abiflags);
+ if (mips_elf_tdata (abfd)->abiflags.version != 0)
+ return FALSE;
+ mips_elf_tdata (abfd)->abiflags_valid = TRUE;
+ }
+
/* FIXME: We should record sh_info for a .gptab section. */
/* For a .reginfo section, set the gp value in the tdata information
@@ -7106,6 +7177,11 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
hdr->sh_entsize = 1;
hdr->sh_flags |= SHF_MIPS_NOSTRIP;
}
+ else if (CONST_STRNEQ (name, ".MIPS.abiflags"))
+ {
+ hdr->sh_type = SHT_MIPS_ABIFLAGS;
+ hdr->sh_entsize = sizeof (Elf_External_ABIFlags_v0);
+ }
else if (CONST_STRNEQ (name, ".debug_")
|| CONST_STRNEQ (name, ".zdebug_"))
{
@@ -9025,7 +9101,7 @@ bfd_boolean
_bfd_mips_elf_always_size_sections (bfd *output_bfd,
struct bfd_link_info *info)
{
- asection *ri;
+ asection *sect;
struct mips_elf_link_hash_table *htab;
struct mips_htab_traverse_info hti;
@@ -9033,9 +9109,14 @@ _bfd_mips_elf_always_size_sections (bfd *output_bfd,
BFD_ASSERT (htab != NULL);
/* The .reginfo section has a fixed size. */
- ri = bfd_get_section_by_name (output_bfd, ".reginfo");
- if (ri != NULL)
- bfd_set_section_size (output_bfd, ri, sizeof (Elf32_External_RegInfo));
+ sect = bfd_get_section_by_name (output_bfd, ".reginfo");
+ if (sect != NULL)
+ bfd_set_section_size (output_bfd, sect, sizeof (Elf32_External_RegInfo));
+
+ /* The .MIPS.abiflags section has a fixed size. */
+ sect = bfd_get_section_by_name (output_bfd, ".MIPS.abiflags");
+ if (sect != NULL)
+ bfd_set_section_size (output_bfd, sect, sizeof (Elf_External_ABIFlags_v0));
hti.info = info;
hti.output_bfd = output_bfd;
@@ -11778,6 +11859,10 @@ _bfd_mips_elf_additional_program_headers (bfd *abfd,
if (s && (s->flags & SEC_LOAD))
++ret;
+ /* See if we need a PT_MIPS_ABIFLAGS segment. */
+ if (bfd_get_section_by_name (abfd, ".MIPS.abiflags"))
+ ++ret;
+
/* See if we need a PT_MIPS_OPTIONS segment. */
if (IRIX_COMPAT (abfd) == ict_irix6
&& bfd_get_section_by_name (abfd,
@@ -11840,6 +11925,37 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
}
}
+ /* If there is a .MIPS.abiflags section, we need a PT_MIPS_ABIFLAGS
+ segment. */
+ s = bfd_get_section_by_name (abfd, ".MIPS.abiflags");
+ if (s != NULL && (s->flags & SEC_LOAD) != 0)
+ {
+ for (m = elf_seg_map (abfd); m != NULL; m = m->next)
+ if (m->p_type == PT_MIPS_ABIFLAGS)
+ break;
+ if (m == NULL)
+ {
+ amt = sizeof *m;
+ m = bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ return FALSE;
+
+ m->p_type = PT_MIPS_ABIFLAGS;
+ m->count = 1;
+ m->sections[0] = s;
+
+ /* We want to put it after the PHDR and INTERP segments. */
+ pm = &elf_seg_map (abfd);
+ while (*pm != NULL
+ && ((*pm)->p_type == PT_PHDR
+ || (*pm)->p_type == PT_INTERP))
+ pm = &(*pm)->next;
+
+ m->next = *pm;
+ *pm = m;
+ }
+ }
+
/* For IRIX 6, we don't have .mdebug sections, nor does anything but
.dynamic end up in PT_DYNAMIC. However, we do have to insert a
PT_MIPS_OPTIONS segment immediately following the program header
@@ -13573,6 +13689,112 @@ _bfd_mips_elf_insn32 (struct bfd_link_info *info, bfd_boolean on)
mips_elf_hash_table (info)->insn32 = on;
}
+/* Update the isa_level and isa_rev fields of abiflags. */
+
+static void
+update_mips_abiflags_isa (bfd *abfd, Elf_Internal_ABIFlags_v0 *abiflags)
+{
+ abiflags->isa_rev = 0;
+ switch (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH)
+ {
+ case E_MIPS_ARCH_1:
+ abiflags->isa_level = 1;
+ break;
+ case E_MIPS_ARCH_2:
+ abiflags->isa_level = 2;
+ break;
+ case E_MIPS_ARCH_3:
+ abiflags->isa_level = 3;
+ break;
+ case E_MIPS_ARCH_4:
+ abiflags->isa_level = 4;
+ break;
+ case E_MIPS_ARCH_5:
+ abiflags->isa_level = 5;
+ break;
+ case E_MIPS_ARCH_32:
+ abiflags->isa_level = 32;
+ abiflags->isa_rev = 1;
+ break;
+ case E_MIPS_ARCH_32R2:
+ abiflags->isa_level = 32;
+ abiflags->isa_rev = 2;
+ break;
+ case E_MIPS_ARCH_64:
+ abiflags->isa_level = 64;
+ abiflags->isa_rev = 1;
+ break;
+ case E_MIPS_ARCH_64R2:
+ abiflags->isa_level = 64;
+ abiflags->isa_rev = 2;
+ break;
+ default:
+ (*_bfd_error_handler)
+ (_("%B: Unknown architecture %s"),
+ abfd, bfd_printable_name (abfd));
+ }
+}
+
+/* Return true if the given ELF header flags describe a 32-bit binary. */
+
+static bfd_boolean
+mips_32bit_flags_p (flagword flags)
+{
+ return ((flags & EF_MIPS_32BITMODE) != 0
+ || (flags & EF_MIPS_ABI) == E_MIPS_ABI_O32
+ || (flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI32
+ || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_1
+ || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_2
+ || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32
+ || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R2);
+}
+
+/* Infer the content of the ABI flags based on the elf header. */
+
+static void
+infer_mips_abiflags (bfd *abfd, Elf_Internal_ABIFlags_v0* abiflags)
+{
+ obj_attribute *in_attr;
+
+ abiflags->version = 0;
+
+ update_mips_abiflags_isa (abfd, abiflags);
+
+ if (mips_32bit_flags_p (elf_elfheader (abfd)->e_flags))
+ abiflags->gpr_size = AFL_REG_32;
+ else
+ abiflags->gpr_size = AFL_REG_64;
+
+ abiflags->cpr1_size = AFL_REG_NONE;
+
+ in_attr = elf_known_obj_attributes (abfd)[OBJ_ATTR_GNU];
+ abiflags->fp_abi = in_attr[Tag_GNU_MIPS_ABI_FP].i;
+
+ if (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_SINGLE
+ || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_XX
+ || (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_DOUBLE
+ && abiflags->gpr_size == AFL_REG_32))
+ abiflags->cpr1_size = AFL_REG_32;
+ else if (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_DOUBLE
+ || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_64)
+ abiflags->cpr1_size = AFL_REG_64;
+
+ abiflags->cpr2_size = AFL_REG_NONE;
+
+ abiflags->isa_ext = 0;
+ abiflags->ases = 0;
+
+ if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MDMX)
+ abiflags->ases |= AFL_ASE_MDMX;
+ if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_M16)
+ abiflags->ases |= AFL_ASE_MIPS16;
+ if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
+ abiflags->ases |= AFL_ASE_MICROMIPS;
+
+ abiflags->flags1 = 0;
+ abiflags->flags2 = 0;
+}
+
/* We need to use a special link routine to handle the .reginfo and
the .mdebug sections. We need to merge all instances of these
sections together, not write them all out sequentially. */
@@ -13583,7 +13805,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
asection *o;
struct bfd_link_order *p;
asection *reginfo_sec, *mdebug_sec, *gptab_data_sec, *gptab_bss_sec;
- asection *rtproc_sec;
+ asection *rtproc_sec, *abiflags_sec;
Elf32_RegInfo reginfo;
struct ecoff_debug_info debug;
struct mips_htab_traverse_info hti;
@@ -13665,12 +13887,47 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
/* Go through the sections and collect the .reginfo and .mdebug
information. */
+ abiflags_sec = NULL;
reginfo_sec = NULL;
mdebug_sec = NULL;
gptab_data_sec = NULL;
gptab_bss_sec = NULL;
for (o = abfd->sections; o != NULL; o = o->next)
{
+ if (strcmp (o->name, ".MIPS.abiflags") == 0)
+ {
+ /* We have found the .MIPS.abiflags section in the output file.
+ Look through all the link_orders comprising it and remove them.
+ The data is merged in _bfd_mips_elf_merge_private_bfd_data. */
+ for (p = o->map_head.link_order; p != NULL; p = p->next)
+ {
+ asection *input_section;
+
+ if (p->type != bfd_indirect_link_order)
+ {
+ if (p->type == bfd_data_link_order)
+ continue;
+ abort ();
+ }
+
+ input_section = p->u.indirect.section;
+
+ /* Hack: reset the SEC_HAS_CONTENTS flag so that
+ elf_link_input_bfd ignores this section. */
+ input_section->flags &= ~SEC_HAS_CONTENTS;
+ }
+
+ /* Size has been set in _bfd_mips_elf_always_size_sections. */
+ BFD_ASSERT(o->size == sizeof (Elf_External_ABIFlags_v0));
+
+ /* Skip this section later on (I don't think this currently
+ matters, but someday it might). */
+ o->map_head.link_order = NULL;
+
+ abiflags_sec = o;
+
+ }
+
if (strcmp (o->name, ".reginfo") == 0)
{
memset (®info, 0, sizeof reginfo);
@@ -14155,6 +14412,24 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
/* Now write out the computed sections. */
+ if (abiflags_sec != NULL)
+ {
+ Elf_External_ABIFlags_v0 ext;
+ Elf_Internal_ABIFlags_v0 *abiflags;
+
+ abiflags = &mips_elf_tdata (abfd)->abiflags;
+
+ /* Set up the abiflags if no valid input sections were found. */
+ if (!mips_elf_tdata (abfd)->abiflags_valid)
+ {
+ infer_mips_abiflags (abfd, abiflags);
+ mips_elf_tdata (abfd)->abiflags_valid = TRUE;
+ }
+ bfd_mips_elf_swap_abiflags_v0_out (abfd, abiflags, &ext);
+ if (! bfd_set_section_contents (abfd, abiflags_sec, &ext, 0, sizeof ext))
+ return FALSE;
+ }
+
if (reginfo_sec != NULL)
{
Elf32_External_RegInfo ext;
@@ -14312,21 +14587,6 @@ mips_mach_extends_p (unsigned long base, unsigned long extension)
}
-/* Return true if the given ELF header flags describe a 32-bit binary. */
-
-static bfd_boolean
-mips_32bit_flags_p (flagword flags)
-{
- return ((flags & EF_MIPS_32BITMODE) != 0
- || (flags & EF_MIPS_ABI) == E_MIPS_ABI_O32
- || (flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI32
- || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_1
- || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_2
- || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32
- || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R2);
-}
-
-
/* Merge object attributes from IBFD into OBFD. Raise an error if
there are conflicting attributes. */
static bfd_boolean
@@ -14385,6 +14645,17 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float");
break;
+ case Val_GNU_MIPS_ABI_FP_OLD_64:
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ "-mdouble-float", "-mips32r2 -mfp64 (12 callee-saved)");
+ break;
+
+ case Val_GNU_MIPS_ABI_FP_XX:
+ /* No change -mfp32 + -mfpxx == -mfp32 */
+ break;
+
case Val_GNU_MIPS_ABI_FP_64:
_bfd_error_handler
(_("Warning: %B uses %s (set by %B), %B uses %s"),
@@ -14417,6 +14688,20 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float");
break;
+ case Val_GNU_MIPS_ABI_FP_OLD_64:
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ "-msingle-float", "-mips32r2 -mfp64 (12 callee-saved)");
+ break;
+
+ case Val_GNU_MIPS_ABI_FP_XX:
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ "-msingle-float", "-mfpxx");
+ break;
+
case Val_GNU_MIPS_ABI_FP_64:
_bfd_error_handler
(_("Warning: %B uses %s (set by %B), %B uses %s"),
@@ -14439,6 +14724,8 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
{
case Val_GNU_MIPS_ABI_FP_DOUBLE:
case Val_GNU_MIPS_ABI_FP_SINGLE:
+ case Val_GNU_MIPS_ABI_FP_OLD_64:
+ case Val_GNU_MIPS_ABI_FP_XX:
case Val_GNU_MIPS_ABI_FP_64:
_bfd_error_handler
(_("Warning: %B uses %s (set by %B), %B uses %s"),
@@ -14455,6 +14742,99 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
}
break;
+ case Val_GNU_MIPS_ABI_FP_OLD_64:
+ switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
+ {
+ case Val_GNU_MIPS_ABI_FP_DOUBLE:
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ "-mips32r2 -mfp64 (12 callee-saved)", "-mdouble-float");
+ break;
+
+ case Val_GNU_MIPS_ABI_FP_SINGLE:
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ "-mips32r2 -mfp64 (12 callee-saved)", "-msingle-float");
+ break;
+
+ case Val_GNU_MIPS_ABI_FP_SOFT:
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float");
+ break;
+
+ case Val_GNU_MIPS_ABI_FP_XX:
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd, "-mips32r2 -mfp64 (12 callee-saved)",
+ "-mfpxx");
+ break;
+
+ case Val_GNU_MIPS_ABI_FP_64:
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd, "-mips32r2 -mfp64 (12 callee-saved)",
+ "-mips32r2 -mfp64");
+ break;
+
+ default:
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), "
+ "%B uses unknown floating point ABI %d"),
+ obfd, abi_fp_bfd, ibfd,
+ "-mips32r2 -mfp64 (12 callee-saved)",
+ in_attr[Tag_GNU_MIPS_ABI_FP].i);
+ break;
+ }
+ break;
+
+ case Val_GNU_MIPS_ABI_FP_XX:
+ switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
+ {
+ case Val_GNU_MIPS_ABI_FP_DOUBLE:
+ /* Update: -mfpxx + -mfp32 == -mfp32. */
+ mips_elf_tdata (obfd)->abi_fp_bfd = ibfd;
+ out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i;
+ break;
+
+ case Val_GNU_MIPS_ABI_FP_SINGLE:
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ "-mfpxx", "-msingle-float");
+ break;
+
+ case Val_GNU_MIPS_ABI_FP_SOFT:
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float");
+ break;
+
+ case Val_GNU_MIPS_ABI_FP_OLD_64:
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd, "-mfpxx",
+ "-mips32r2 -mfp64 (12 callee-saved)");
+ break;
+
+ case Val_GNU_MIPS_ABI_FP_64:
+ /* Update: -mfpxx + -mfp64 == -mfp64. */
+ mips_elf_tdata (obfd)->abi_fp_bfd = ibfd;
+ out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i;
+ break;
+
+ default:
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), "
+ "%B uses unknown floating point ABI %d"),
+ obfd, abi_fp_bfd, ibfd,
+ "-mfpxx", in_attr[Tag_GNU_MIPS_ABI_FP].i);
+ break;
+ }
+ break;
+
case Val_GNU_MIPS_ABI_FP_64:
switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
{
@@ -14478,6 +14858,17 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float");
break;
+ case Val_GNU_MIPS_ABI_FP_OLD_64:
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd, "-mips32r2 -mfp64",
+ "-mips32r2 -mfp64 (12 callee-saved)");
+ break;
+
+ case Val_GNU_MIPS_ABI_FP_XX:
+ /* No change -mfp64 + -mfpxx == -mfp64 */
+ break;
+
default:
_bfd_error_handler
(_("Warning: %B uses %s (set by %B), "
@@ -14515,6 +14906,23 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
out_attr[Tag_GNU_MIPS_ABI_FP].i, "-msoft-float");
break;
+ case Val_GNU_MIPS_ABI_FP_OLD_64:
+ _bfd_error_handler
+ (_("Warning: %B uses unknown floating point ABI %d "
+ "(set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ out_attr[Tag_GNU_MIPS_ABI_FP].i,
+ "-mips32r2 -mfp64 (12 callee-saved)");
+ break;
+
+ case Val_GNU_MIPS_ABI_FP_XX:
+ _bfd_error_handler
+ (_("Warning: %B uses unknown floating point ABI %d "
+ "(set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ out_attr[Tag_GNU_MIPS_ABI_FP].i, "-mfpxx");
+ break;
+
case Val_GNU_MIPS_ABI_FP_64:
_bfd_error_handler
(_("Warning: %B uses unknown floating point ABI %d "
@@ -14615,6 +15023,16 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
return FALSE;
}
+ /* Set up the FP ABI attribute from the abiflags if it is not already
+ set. */
+ if (mips_elf_tdata (ibfd)->abiflags_valid)
+ {
+ obj_attribute *in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
+ if (in_attr[Tag_GNU_MIPS_ABI_FP].i == Val_GNU_MIPS_ABI_FP_ANY)
+ in_attr[Tag_GNU_MIPS_ABI_FP].i =
+ mips_elf_tdata (ibfd)->abiflags.fp_abi;
+ }
+
if (!mips_elf_merge_obj_attributes (ibfd, obfd))
return FALSE;
@@ -14622,26 +15040,6 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER;
old_flags = elf_elfheader (obfd)->e_flags;
- if (! elf_flags_init (obfd))
- {
- elf_flags_init (obfd) = TRUE;
- elf_elfheader (obfd)->e_flags = new_flags;
- elf_elfheader (obfd)->e_ident[EI_CLASS]
- = elf_elfheader (ibfd)->e_ident[EI_CLASS];
-
- if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
- && (bfd_get_arch_info (obfd)->the_default
- || mips_mach_extends_p (bfd_get_mach (obfd),
- bfd_get_mach (ibfd))))
- {
- if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
- bfd_get_mach (ibfd)))
- return FALSE;
- }
-
- return TRUE;
- }
-
/* Check flag compatibility. */
new_flags &= ~EF_MIPS_NOREORDER;
@@ -14661,9 +15059,6 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
if ((ibfd->flags & DYNAMIC) != 0)
new_flags |= EF_MIPS_PIC | EF_MIPS_CPIC;
- if (new_flags == old_flags)
- return TRUE;
-
/* Check to see if the input BFD actually contains any sections.
If not, its flags may not have been initialised either, but it cannot
actually cause any incompatibility. */
@@ -14688,6 +15083,86 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
if (null_input_bfd)
return TRUE;
+ /* Populate abiflags using existing information. */
+ if (!mips_elf_tdata (ibfd)->abiflags_valid)
+ {
+ infer_mips_abiflags (ibfd, &mips_elf_tdata (ibfd)->abiflags);
+ mips_elf_tdata (ibfd)->abiflags_valid = TRUE;
+ }
+ else
+ {
+ Elf_Internal_ABIFlags_v0 abiflags;
+ Elf_Internal_ABIFlags_v0 *iabiflags;
+ infer_mips_abiflags (ibfd, &abiflags);
+ iabiflags = &mips_elf_tdata (ibfd)->abiflags;
+
+ if (iabiflags->isa_level != abiflags.isa_level
+ || iabiflags->isa_rev != abiflags.isa_rev)
+ (*_bfd_error_handler)
+ (_("%B: warning: Inconsistent ISA between e_flags and "
+ ".MIPS.abiflags"), ibfd);
+ if (abiflags.fp_abi != Val_GNU_MIPS_ABI_FP_ANY
+ && iabiflags->fp_abi != abiflags.fp_abi)
+ (*_bfd_error_handler)
+ (_("%B: warning: Inconsistent FP ABI between e_flags and "
+ ".MIPS.abiflags"), ibfd);
+ if ((iabiflags->ases & abiflags.ases) != abiflags.ases)
+ (*_bfd_error_handler)
+ (_("%B: warning: Inconsistent ASEs between e_flags and "
+ ".MIPS.abiflags"), ibfd);
+ }
+
+ if (!mips_elf_tdata (obfd)->abiflags_valid)
+ {
+ /* Copy input abiflags if output abiflags are not already valid. */
+ mips_elf_tdata (obfd)->abiflags = mips_elf_tdata (ibfd)->abiflags;
+ mips_elf_tdata (obfd)->abiflags_valid = TRUE;
+ }
+
+ if (! elf_flags_init (obfd))
+ {
+ elf_flags_init (obfd) = TRUE;
+ elf_elfheader (obfd)->e_flags = new_flags;
+ elf_elfheader (obfd)->e_ident[EI_CLASS]
+ = elf_elfheader (ibfd)->e_ident[EI_CLASS];
+
+ if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
+ && (bfd_get_arch_info (obfd)->the_default
+ || mips_mach_extends_p (bfd_get_mach (obfd),
+ bfd_get_mach (ibfd))))
+ {
+ if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
+ bfd_get_mach (ibfd)))
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ /* Update the output abiflags fp_abi using the computed fp_abi. */
+ obj_attribute *out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
+ mips_elf_tdata (obfd)->abiflags.fp_abi = out_attr[Tag_GNU_MIPS_ABI_FP].i;
+
+#define max(a,b) ((a) > (b) ? (a) : (b))
+ /* Merge abiflags. */
+ mips_elf_tdata (obfd)->abiflags.gpr_size
+ = max (mips_elf_tdata (obfd)->abiflags.gpr_size,
+ mips_elf_tdata (ibfd)->abiflags.gpr_size);
+ mips_elf_tdata (obfd)->abiflags.cpr1_size
+ = max (mips_elf_tdata (obfd)->abiflags.cpr1_size,
+ mips_elf_tdata (ibfd)->abiflags.cpr1_size);
+ mips_elf_tdata (obfd)->abiflags.cpr2_size
+ = max (mips_elf_tdata (obfd)->abiflags.cpr2_size,
+ mips_elf_tdata (ibfd)->abiflags.cpr2_size);
+#undef max
+ mips_elf_tdata (obfd)->abiflags.ases
+ |= mips_elf_tdata (ibfd)->abiflags.ases;
+ mips_elf_tdata (obfd)->abiflags.isa_ext
+ |= mips_elf_tdata (ibfd)->abiflags.isa_ext;
+
+ if (new_flags == old_flags)
+ return TRUE;
+
ok = TRUE;
if (((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0)
@@ -14728,6 +15203,9 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
elf_elfheader (obfd)->e_flags
|= new_flags & (EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE);
+ /* Update the ABI flags isa_level and isa_rev fields. */
+ update_mips_abiflags_isa (obfd, &mips_elf_tdata (obfd)->abiflags);
+
/* Copy across the ABI flags if OBFD doesn't use them
and if that was what caused us to treat IBFD as 32-bit. */
if ((old_flags & EF_MIPS_ABI) == 0
@@ -14813,6 +15291,20 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
old_flags &= ~EF_MIPS_NAN2008;
}
+ /* Compare FP64 state. */
+ if ((new_flags & EF_MIPS_FP64) != (old_flags & EF_MIPS_FP64))
+ {
+ _bfd_error_handler (_("%B: linking %s module with previous %s modules"),
+ ibfd,
+ (new_flags & EF_MIPS_FP64
+ ? "-mfp64" : "-mfp32"),
+ (old_flags & EF_MIPS_FP64
+ ? "-mfp64" : "-mfp32"));
+ ok = FALSE;
+ new_flags &= ~EF_MIPS_FP64;
+ old_flags &= ~EF_MIPS_FP64;
+ }
+
/* Warn about any other mismatches */
if (new_flags != old_flags)
{
@@ -14944,6 +15436,130 @@ _bfd_mips_elf_get_target_dtag (bfd_vma dtag)
}
}
+static void
+print_mips_ases (FILE *file, unsigned int mask)
+{
+ if (mask & AFL_ASE_DSP)
+ fputs ("\n\tDSP ASE", file);
+ if (mask & AFL_ASE_DSP64)
+ fputs ("\n\tDSP ASE (64-bit)", file);
+ if (mask & AFL_ASE_DSPR2)
+ fputs ("\n\tDSP R2 ASE", file);
+ if (mask & AFL_ASE_EVA)
+ fputs ("\n\tEnhanced VA Scheme", file);
+ if (mask & AFL_ASE_MCU)
+ fputs ("\n\tMCU (MicroController) ASE", file);
+ if (mask & AFL_ASE_MDMX)
+ fputs ("\n\tMDMX ASE", file);
+ if (mask & AFL_ASE_MIPS3D)
+ fputs ("\n\tMIPS-3D ASE", file);
+ if (mask & AFL_ASE_MT)
+ fputs ("\n\tMT ASE", file);
+ if (mask & AFL_ASE_SMARTMIPS)
+ fputs ("\n\tSmartMIPS ASE", file);
+ if (mask & AFL_ASE_VIRT)
+ fputs ("\n\tVZ ASE", file);
+ if (mask & AFL_ASE_VIRT64)
+ fputs ("\n\tVZ ASE (64-bit)", file);
+ if (mask & AFL_ASE_MSA)
+ fputs ("\n\tMSA ASE", file);
+ if (mask & AFL_ASE_MSA64)
+ fputs ("\n\tMSA ASE (64-bit)", file);
+ if (mask & AFL_ASE_MIPS16)
+ fputs ("\n\tMIPS16 ASE", file);
+ if (mask & AFL_ASE_MICROMIPS)
+ fputs ("\n\tMICROMIPS ASE", file);
+ if (mask & AFL_ASE_XPA)
+ fputs ("\n\tXPA ASE", file);
+ if (mask == 0)
+ fputs ("\n\tNone", file);
+}
+
+static void
+print_mips_isa_ext (FILE *file, unsigned int mask)
+{
+ if (mask & AFL_EXT_XLR)
+ fputs ("\n\tRMI Xlr instruction", file);
+ if (mask & AFL_EXT_OCTEON2)
+ fputs ("\n\tCavium Networks Octeon2", file);
+ if (mask & AFL_EXT_OCTEONP)
+ fputs ("\n\tCavium Networks OcteonP", file);
+ if (mask & AFL_EXT_LOONGSON_3A)
+ fputs ("\n\tLoongson 3A", file);
+ if (mask & AFL_EXT_OCTEON)
+ fputs ("\n\tCavium Networks Octeon", file);
+ if (mask & AFL_EXT_5900)
+ fputs ("\n\tMIPS R5900", file);
+ if (mask & AFL_EXT_4650)
+ fputs ("\n\tMIPS R4650", file);
+ if (mask & AFL_EXT_4010)
+ fputs ("\n\tLSI R4010", file);
+ if (mask & AFL_EXT_4100)
+ fputs ("\n\tNEC VR4100", file);
+ if (mask & AFL_EXT_3900)
+ fputs ("\n\tToshiba R3900", file);
+ if (mask & AFL_EXT_10000)
+ fputs ("\n\tMIPS R10000", file);
+ if (mask & AFL_EXT_SB1)
+ fputs ("\n\tBroadcom SB-1", file);
+ if (mask & AFL_EXT_4111)
+ fputs ("\n\tNEC VR4111/VR4181", file);
+ if (mask & AFL_EXT_4120)
+ fputs ("\n\tNEC VR4120", file);
+ if (mask & AFL_EXT_5400)
+ fputs ("\n\tNEC VR5400", file);
+ if (mask & AFL_EXT_5500)
+ fputs ("\n\tNEC VR5500", file);
+ if (mask & AFL_EXT_LOONGSON_2E)
+ fputs ("\n\tST Microelectronics Loongson 2E", file);
+ if (mask & AFL_EXT_LOONGSON_2F)
+ fputs ("\n\tST Microelectronics Loongson 2F", file);
+ if (mask == 0)
+ fputs ("\n\tNone", file);
+}
+
+static void
+print_mips_fp_abi_value (FILE *file, int val)
+{
+ switch (val)
+ {
+ case Val_GNU_MIPS_ABI_FP_ANY:
+ fprintf (file, _("Hard or soft float\n"));
+ break;
+ case Val_GNU_MIPS_ABI_FP_DOUBLE:
+ fprintf (file, _("Hard float (double precision)\n"));
+ break;
+ case Val_GNU_MIPS_ABI_FP_SINGLE:
+ fprintf (file, _("Hard float (single precision)\n"));
+ break;
+ case Val_GNU_MIPS_ABI_FP_SOFT:
+ fprintf (file, _("Soft float\n"));
+ break;
+ case Val_GNU_MIPS_ABI_FP_OLD_64:
+ fprintf (file, _("Hard float (MIPS32r2 64-bit FPU 12 callee-saved)\n"));
+ break;
+ case Val_GNU_MIPS_ABI_FP_XX:
+ fprintf (file, _("Hard float (32-bit CPU, Any FPU)\n"));
+ break;
+ case Val_GNU_MIPS_ABI_FP_64:
+ fprintf (file, _("Hard float (32-bit CPU, 64-bit FPU)\n"));
+ break;
+ default:
+ fprintf (file, "??? (%d)\n", val);
+ break;
+ }
+}
+
+static int
+get_mips_reg_size (int reg_size)
+{
+ return (reg_size == AFL_REG_NONE) ? 0
+ : (reg_size == AFL_REG_32) ? 32
+ : (reg_size == AFL_REG_64) ? 64
+ : (reg_size == AFL_REG_128) ? 128
+ : -1;
+}
+
bfd_boolean
_bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
{
@@ -15008,7 +15624,7 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
fprintf (file, " [nan2008]");
if (elf_elfheader (abfd)->e_flags & EF_MIPS_FP64)
- fprintf (file, " [fp64]");
+ fprintf (file, " [old fp64]");
if (elf_elfheader (abfd)->e_flags & EF_MIPS_32BITMODE)
fprintf (file, " [32bitmode]");
@@ -15032,6 +15648,30 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
fputc ('\n', file);
+ if (mips_elf_tdata (abfd)->abiflags_valid)
+ {
+ Elf_Internal_ABIFlags_v0 *abiflags = &mips_elf_tdata (abfd)->abiflags;
+ fprintf (file, "\nMIPS ABI Flags Version: %d\n", abiflags->version);
+ fprintf (file, "\nISA: MIPS%d", abiflags->isa_level);
+ if (abiflags->isa_rev != 0)
+ fprintf (file, "r%d", abiflags->isa_rev);
+ fprintf (file, "\nGPR size: %d",
+ get_mips_reg_size (abiflags->gpr_size));
+ fprintf (file, "\nCPR1 size: %d",
+ get_mips_reg_size (abiflags->cpr1_size));
+ fprintf (file, "\nCPR2 size: %d",
+ get_mips_reg_size (abiflags->cpr2_size));
+ fputs ("\nFP ABI: ", file);
+ print_mips_fp_abi_value (file, abiflags->fp_abi);
+ fputs ("ISA Extensions:", file);
+ print_mips_isa_ext (file, abiflags->isa_ext);
+ fputs ("\nASEs:", file);
+ print_mips_ases (file, abiflags->ases);
+ fprintf (file, "\nFLAGS 1: %8.8lx", abiflags->flags1);
+ fprintf (file, "\nFLAGS 2: %8.8lx", abiflags->flags2);
+ fputc ('\n', file);
+ }
+
return TRUE;
}
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 9cafd7c..6c3ef70 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -3165,6 +3165,8 @@ get_mips_segment_type (unsigned long type)
return "RTPROC";
case PT_MIPS_OPTIONS:
return "OPTIONS";
+ case PT_MIPS_ABIFLAGS:
+ return "ABIFLAGS";
default:
break;
}
@@ -3364,6 +3366,7 @@ get_mips_section_type_name (unsigned int sh_type)
case SHT_MIPS_EH_REGION: return "MIPS_EH_REGION";
case SHT_MIPS_XLATE_OLD: return "MIPS_XLATE_OLD";
case SHT_MIPS_PDR_EXCEPTION: return "MIPS_PDR_EXCEPTION";
+ case SHT_MIPS_ABIFLAGS: return "MIPS_ABIFLAGS";
default:
break;
}
@@ -11993,6 +11996,38 @@ display_sparc_gnu_attribute (unsigned char * p,
return display_tag_value (tag, p, end);
}
+static void
+print_mips_fp_abi_value (int val)
+{
+ switch (val)
+ {
+ case Val_GNU_MIPS_ABI_FP_ANY:
+ printf (_("Hard or soft float\n"));
+ break;
+ case Val_GNU_MIPS_ABI_FP_DOUBLE:
+ printf (_("Hard float (double precision)\n"));
+ break;
+ case Val_GNU_MIPS_ABI_FP_SINGLE:
+ printf (_("Hard float (single precision)\n"));
+ break;
+ case Val_GNU_MIPS_ABI_FP_SOFT:
+ printf (_("Soft float\n"));
+ break;
+ case Val_GNU_MIPS_ABI_FP_OLD_64:
+ printf (_("Hard float (MIPS32r2 64-bit FPU 12 callee-saved)\n"));
+ break;
+ case Val_GNU_MIPS_ABI_FP_XX:
+ printf (_("Hard float (32-bit CPU, Any FPU)\n"));
+ break;
+ case Val_GNU_MIPS_ABI_FP_64:
+ printf (_("Hard float (32-bit CPU, 64-bit FPU)\n"));
+ break;
+ default:
+ printf ("??? (%d)\n", val);
+ break;
+ }
+}
+
static unsigned char *
display_mips_gnu_attribute (unsigned char * p,
int tag,
@@ -12007,27 +12042,8 @@ display_mips_gnu_attribute (unsigned char * p,
p += len;
printf (" Tag_GNU_MIPS_ABI_FP: ");
- switch (val)
- {
- case Val_GNU_MIPS_ABI_FP_ANY:
- printf (_("Hard or soft float\n"));
- break;
- case Val_GNU_MIPS_ABI_FP_DOUBLE:
- printf (_("Hard float (double precision)\n"));
- break;
- case Val_GNU_MIPS_ABI_FP_SINGLE:
- printf (_("Hard float (single precision)\n"));
- break;
- case Val_GNU_MIPS_ABI_FP_SOFT:
- printf (_("Soft float\n"));
- break;
- case Val_GNU_MIPS_ABI_FP_64:
- printf (_("Hard float (MIPS32r2 64-bit FPU)\n"));
- break;
- default:
- printf ("??? (%d)\n", val);
- break;
- }
+ print_mips_fp_abi_value (val);
+
return p;
}
@@ -12630,10 +12646,103 @@ print_mips_pltgot_entry (unsigned char * data, bfd_vma pltgot, bfd_vma addr)
return addr + (is_32bit_elf ? 4 : 8);
}
+static void
+print_mips_ases (unsigned int mask)
+{
+ if (mask & AFL_ASE_DSP)
+ fputs ("\n\tDSP ASE", stdout);
+ if (mask & AFL_ASE_DSP64)
+ fputs ("\n\tDSP ASE (64-bit)", stdout);
+ if (mask & AFL_ASE_DSPR2)
+ fputs ("\n\tDSP R2 ASE", stdout);
+ if (mask & AFL_ASE_EVA)
+ fputs ("\n\tEnhanced VA Scheme", stdout);
+ if (mask & AFL_ASE_MCU)
+ fputs ("\n\tMCU (MicroController) ASE", stdout);
+ if (mask & AFL_ASE_MDMX)
+ fputs ("\n\tMDMX ASE", stdout);
+ if (mask & AFL_ASE_MIPS3D)
+ fputs ("\n\tMIPS-3D ASE", stdout);
+ if (mask & AFL_ASE_MT)
+ fputs ("\n\tMT ASE", stdout);
+ if (mask & AFL_ASE_SMARTMIPS)
+ fputs ("\n\tSmartMIPS ASE", stdout);
+ if (mask & AFL_ASE_VIRT)
+ fputs ("\n\tVZ ASE", stdout);
+ if (mask & AFL_ASE_VIRT64)
+ fputs ("\n\tVZ ASE (64-bit)", stdout);
+ if (mask & AFL_ASE_MSA)
+ fputs ("\n\tMSA ASE", stdout);
+ if (mask & AFL_ASE_MSA64)
+ fputs ("\n\tMSA ASE (64-bit)", stdout);
+ if (mask & AFL_ASE_MIPS16)
+ fputs ("\n\tMIPS16 ASE", stdout);
+ if (mask & AFL_ASE_MICROMIPS)
+ fputs ("\n\tMICROMIPS ASE", stdout);
+ if (mask & AFL_ASE_XPA)
+ fputs ("\n\tXPA ASE", stdout);
+ if (mask == 0)
+ fputs ("\n\tNone", stdout);
+}
+
+static void
+print_mips_isa_ext (unsigned int mask)
+{
+ if (mask & AFL_EXT_XLR)
+ fputs ("\n\tRMI Xlr instruction", stdout);
+ if (mask & AFL_EXT_OCTEON2)
+ fputs ("\n\tCavium Networks Octeon2", stdout);
+ if (mask & AFL_EXT_OCTEONP)
+ fputs ("\n\tCavium Networks OcteonP", stdout);
+ if (mask & AFL_EXT_LOONGSON_3A)
+ fputs ("\n\tLoongson 3A", stdout);
+ if (mask & AFL_EXT_OCTEON)
+ fputs ("\n\tCavium Networks Octeon", stdout);
+ if (mask & AFL_EXT_5900)
+ fputs ("\n\tMIPS R5900", stdout);
+ if (mask & AFL_EXT_4650)
+ fputs ("\n\tMIPS R4650", stdout);
+ if (mask & AFL_EXT_4010)
+ fputs ("\n\tLSI R4010", stdout);
+ if (mask & AFL_EXT_4100)
+ fputs ("\n\tNEC VR4100", stdout);
+ if (mask & AFL_EXT_3900)
+ fputs ("\n\tToshiba R3900", stdout);
+ if (mask & AFL_EXT_10000)
+ fputs ("\n\tMIPS R10000", stdout);
+ if (mask & AFL_EXT_SB1)
+ fputs ("\n\tBroadcom SB-1", stdout);
+ if (mask & AFL_EXT_4111)
+ fputs ("\n\tNEC VR4111/VR4181", stdout);
+ if (mask & AFL_EXT_4120)
+ fputs ("\n\tNEC VR4120", stdout);
+ if (mask & AFL_EXT_5400)
+ fputs ("\n\tNEC VR5400", stdout);
+ if (mask & AFL_EXT_5500)
+ fputs ("\n\tNEC VR5500", stdout);
+ if (mask & AFL_EXT_LOONGSON_2E)
+ fputs ("\n\tST Microelectronics Loongson 2E", stdout);
+ if (mask & AFL_EXT_LOONGSON_2F)
+ fputs ("\n\tST Microelectronics Loongson 2F", stdout);
+ if (mask == 0)
+ fputs ("\n\tNone", stdout);
+}
+
+static int
+get_mips_reg_size (int reg_size)
+{
+ return (reg_size == AFL_REG_NONE) ? 0
+ : (reg_size == AFL_REG_32) ? 32
+ : (reg_size == AFL_REG_64) ? 64
+ : (reg_size == AFL_REG_128) ? 128
+ : -1;
+}
+
static int
process_mips_specific (FILE * file)
{
Elf_Internal_Dyn * entry;
+ Elf_Internal_Shdr *sect = NULL;
size_t liblist_offset = 0;
size_t liblistno = 0;
size_t conflictsno = 0;
@@ -12651,6 +12760,57 @@ process_mips_specific (FILE * file)
process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL,
display_mips_gnu_attribute);
+ sect = find_section (".MIPS.abiflags");
+
+ if (sect != NULL)
+ {
+ Elf_External_ABIFlags_v0 *abiflags_ext;
+ Elf_Internal_ABIFlags_v0 abiflags_in;
+
+ if (sizeof (Elf_External_ABIFlags_v0) != sect->sh_size)
+ fputs ("\nCorrupt ABI Flags section.\n", stdout);
+ else
+ {
+ abiflags_ext = get_data (NULL, file, sect->sh_offset, 1,
+ sect->sh_size, _("MIPS ABI Flags section"));
+ if (abiflags_ext)
+ {
+ abiflags_in.version = BYTE_GET (abiflags_ext->version);
+ abiflags_in.isa_level = BYTE_GET (abiflags_ext->isa_level);
+ abiflags_in.isa_rev = BYTE_GET (abiflags_ext->isa_rev);
+ abiflags_in.gpr_size = BYTE_GET (abiflags_ext->gpr_size);
+ abiflags_in.cpr1_size = BYTE_GET (abiflags_ext->cpr1_size);
+ abiflags_in.cpr2_size = BYTE_GET (abiflags_ext->cpr2_size);
+ abiflags_in.fp_abi = BYTE_GET (abiflags_ext->fp_abi);
+ abiflags_in.isa_ext = BYTE_GET (abiflags_ext->isa_ext);
+ abiflags_in.ases = BYTE_GET (abiflags_ext->ases);
+ abiflags_in.flags1 = BYTE_GET (abiflags_ext->flags1);
+ abiflags_in.flags2 = BYTE_GET (abiflags_ext->flags2);
+
+ printf ("\nMIPS ABI Flags Version: %d\n", abiflags_in.version);
+ printf ("\nISA: MIPS%d", abiflags_in.isa_level);
+ if (abiflags_in.isa_rev != 0)
+ printf ("r%d", abiflags_in.isa_rev);
+ printf ("\nGPR size: %d",
+ get_mips_reg_size (abiflags_in.gpr_size));
+ printf ("\nCPR1 size: %d",
+ get_mips_reg_size (abiflags_in.cpr1_size));
+ printf ("\nCPR2 size: %d",
+ get_mips_reg_size (abiflags_in.cpr2_size));
+ fputs ("\nFP ABI: ", stdout);
+ print_mips_fp_abi_value (abiflags_in.fp_abi);
+ fputs ("ISA Extensions:", stdout);
+ print_mips_isa_ext (abiflags_in.isa_ext);
+ fputs ("\nASEs:", stdout);
+ print_mips_ases (abiflags_in.ases);
+ printf ("\nFLAGS 1: %8.8lx", abiflags_in.flags1);
+ printf ("\nFLAGS 2: %8.8lx", abiflags_in.flags2);
+ fputc ('\n', stdout);
+ free (abiflags_ext);
+ }
+ }
+ }
+
/* We have a lot of special sections. Thanks SGI! */
if (dynamic_section == NULL)
/* No information available. */
@@ -12790,11 +12950,11 @@ process_mips_specific (FILE * file)
if (options_offset != 0)
{
Elf_External_Options * eopt;
- Elf_Internal_Shdr * sect = section_headers;
Elf_Internal_Options * iopt;
Elf_Internal_Options * option;
size_t offset;
int cnt;
+ sect = section_headers;
/* Find the section header so that we get the size. */
while (sect->sh_type != SHT_MIPS_OPTIONS)
diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h
index 561b54a..1c48bd5 100644
--- a/elfcpp/elfcpp.h
+++ b/elfcpp/elfcpp.h
@@ -490,7 +490,9 @@ enum PT
// Runtime procedure table.
PT_MIPS_RTPROC = 0x70000001,
// .MIPS.options section.
- PT_MIPS_OPTIONS = 0x70000002
+ PT_MIPS_OPTIONS = 0x70000002,
+ // .MIPS.abiflags section.
+ PT_MIPS_ABIFLAGS = 0x70000003
};
// The valid bit flags found in the Phdr p_flags field.
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index 960169e..f63d31c 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -42,6 +42,8 @@ typedef char static_assert2[sizeof (valueT) < 8 ? -1 : 1];
#define DBG(x)
#endif
+#define streq(a, b) (strcmp (a, b) == 0)
+
#define SKIP_SPACE_TABS(S) \
do { while (*(S) == ' ' || *(S) == '\t') ++(S); } while (0)
@@ -87,6 +89,7 @@ int mips_flag_pdr = TRUE;
#include "ecoff.h"
static char *mips_regmask_frag;
+static char *mips_flags_frag;
#define ZERO 0
#define ATREG 1
@@ -240,7 +243,7 @@ struct mips_set_options
to 32 bit. This is initially determined when -mgp32 or -mfp32
is passed but can changed if the assembler code uses .set mipsN. */
int gp32;
- int fp32;
+ int fp;
/* MIPS architecture (CPU) type. Changed by .set arch=FOO, the -march
command line option, and the default CPU. */
int arch;
@@ -255,34 +258,50 @@ struct mips_set_options
Changed by .set singlefloat or .set doublefloat, command-line options
-msingle-float or -mdouble-float. The default is false. */
bfd_boolean single_float;
+
+ /* Set when an FP mode is entered that is incompatible with the overall
+ module's mode. This is a potential error if floating point code goes
+ on to be emitted that uses odd numbered single precision registers. A
+ warning is generated if this then happens prior to re-entering a region
+ with a compatible FP mode. */
+ bfd_boolean mips_defer_fp_warn;
};
-/* This is the struct we use to hold the current set of options. Note
- that we must set the isa field to ISA_UNKNOWN and the ASE fields to
- -1 to indicate that they have not been initialized. */
+/* Specifies whether FP code has been seen. */
+static bfd_boolean mips_seen_fp_code = FALSE;
-/* True if -mgp32 was passed. */
-static int file_mips_gp32 = -1;
+/* Specifies whether module level options have been checked yet. */
+static bfd_boolean file_mips_opts_checked = FALSE;
-/* True if -mfp32 was passed. */
-static int file_mips_fp32 = -1;
+/* True if -mnan=2008, false if -mnan=legacy. */
+static bfd_boolean mips_flag_nan2008 = FALSE;
-/* 1 if -msoft-float, 0 if -mhard-float. The default is 0. */
-static int file_mips_soft_float = 0;
+/* This is the struct we use to hold the module level set of options. Note
+ that we must set the isa field to ISA_UNKNOWN and the ASE fields to
+ -1 to indicate that they have not been initialized. */
-/* 1 if -msingle-float, 0 if -mdouble-float. The default is 0. */
-static int file_mips_single_float = 0;
+static struct mips_set_options file_mips_opts =
+{
+ /* isa */ ISA_UNKNOWN, /* ase */ 0, /* mips16 */ -1, /* micromips */ -1,
+ /* noreorder */ 0, /* at */ ATREG, /* warn_about_macros */ 0,
+ /* nomove */ 0, /* nobopt */ 0, /* noautoextend */ 0, /* insn32 */ FALSE,
+ /* gp32 */ -1, /* fp */ -1, /* arch */ CPU_UNKNOWN, /* sym32 */ FALSE,
+ /* soft_float */ FALSE, /* single_float */ FALSE,
+ /* mips_defer_fp_warn */ FALSE
+};
-/* True if -mnan=2008, false if -mnan=legacy. */
-static bfd_boolean mips_flag_nan2008 = FALSE;
+/* This is the struct we use to hold the current set of options. Note
+ that we must set the isa field to ISA_UNKNOWN and the ASE fields to
+ -1 to indicate that they have not been initialized. */
static struct mips_set_options mips_opts =
{
/* isa */ ISA_UNKNOWN, /* ase */ 0, /* mips16 */ -1, /* micromips */ -1,
/* noreorder */ 0, /* at */ ATREG, /* warn_about_macros */ 0,
/* nomove */ 0, /* nobopt */ 0, /* noautoextend */ 0, /* insn32 */ FALSE,
- /* gp32 */ 0, /* fp32 */ 0, /* arch */ CPU_UNKNOWN, /* sym32 */ FALSE,
- /* soft_float */ FALSE, /* single_float */ FALSE
+ /* gp32 */ -1, /* fp */ -1, /* arch */ CPU_UNKNOWN, /* sym32 */ FALSE,
+ /* soft_float */ FALSE, /* single_float */ FALSE,
+ /* mips_defer_fp_warn */ FALSE
};
/* The set of ASEs that were selected on the command line, either
@@ -298,9 +317,6 @@ static unsigned int file_ase_explicit;
unsigned long mips_gprmask;
unsigned long mips_cprmask[4];
-/* MIPS ISA we are using for this output file. */
-static int file_mips_isa = ISA_UNKNOWN;
-
/* True if any MIPS16 code was produced. */
static int file_ase_mips16;
@@ -325,7 +341,6 @@ static int file_ase_micromips;
#endif
/* The argument of the -march= flag. The architecture we are assembling. */
-static int file_mips_arch = CPU_UNKNOWN;
static const char *mips_arch_string;
/* The argument of the -mtune= flag. The architecture for which we
@@ -375,7 +390,7 @@ static int mips_32bitmode = 0;
#define ISA_HAS_ROR(ISA) \
((ISA) == ISA_MIPS32R2 \
|| (ISA) == ISA_MIPS64R2 \
- || (mips_opts.ase & ASE_SMARTMIPS) \
+ || (mips_opts.ase & AFL_ASE_SMARTMIPS) \
|| mips_opts.micromips \
)
@@ -396,7 +411,7 @@ static int mips_32bitmode = 0;
(mips_opts.gp32 || !ISA_HAS_64BIT_REGS (mips_opts.isa))
#define HAVE_32BIT_FPRS \
- (mips_opts.fp32 || !ISA_HAS_64BIT_FPRS (mips_opts.isa))
+ (mips_opts.fp != 64 || !ISA_HAS_64BIT_FPRS (mips_opts.isa))
#define HAVE_64BIT_GPRS (!HAVE_32BIT_GPRS)
#define HAVE_64BIT_FPRS (!HAVE_32BIT_FPRS)
@@ -1269,6 +1284,7 @@ static void s_ehword (int);
static void s_cpadd (int);
static void s_insn (int);
static void s_nan (int);
+static void s_module (int);
static void md_obj_begin (void);
static void md_obj_end (void);
static void s_mips_ent (int);
@@ -1378,6 +1394,7 @@ enum options
OPTION_CONSTRUCT_FLOATS,
OPTION_NO_CONSTRUCT_FLOATS,
OPTION_FP64,
+ OPTION_FPXX,
OPTION_GP64,
OPTION_RELAX_BRANCH,
OPTION_NO_RELAX_BRANCH,
@@ -1493,6 +1510,7 @@ struct option md_longopts[] =
{"construct-floats", no_argument, NULL, OPTION_CONSTRUCT_FLOATS},
{"no-construct-floats", no_argument, NULL, OPTION_NO_CONSTRUCT_FLOATS},
{"mfp64", no_argument, NULL, OPTION_FP64},
+ {"mfpxx", no_argument, NULL, OPTION_FPXX},
{"mgp64", no_argument, NULL, OPTION_GP64},
{"relax-branch", no_argument, NULL, OPTION_RELAX_BRANCH},
{"no-relax-branch", no_argument, NULL, OPTION_NO_RELAX_BRANCH},
@@ -1563,59 +1581,59 @@ struct mips_ase
/* A table of all supported ASEs. */
static const struct mips_ase mips_ases[] = {
- { "dsp", ASE_DSP, ASE_DSP64,
+ { "dsp", AFL_ASE_DSP, AFL_ASE_DSP64,
OPTION_DSP, OPTION_NO_DSP,
2, 2, 2, 2 },
- { "dspr2", ASE_DSP | ASE_DSPR2, 0,
+ { "dspr2", AFL_ASE_DSP | AFL_ASE_DSPR2, 0,
OPTION_DSPR2, OPTION_NO_DSPR2,
2, 2, 2, 2 },
- { "eva", ASE_EVA, 0,
+ { "eva", AFL_ASE_EVA, 0,
OPTION_EVA, OPTION_NO_EVA,
2, 2, 2, 2 },
- { "mcu", ASE_MCU, 0,
+ { "mcu", AFL_ASE_MCU, 0,
OPTION_MCU, OPTION_NO_MCU,
2, 2, 2, 2 },
/* Deprecated in MIPS64r5, but we don't implement that yet. */
- { "mdmx", ASE_MDMX, 0,
+ { "mdmx", AFL_ASE_MDMX, 0,
OPTION_MDMX, OPTION_NO_MDMX,
-1, 1, -1, -1 },
/* Requires 64-bit FPRs, so the minimum MIPS32 revision is 2. */
- { "mips3d", ASE_MIPS3D, 0,
+ { "mips3d", AFL_ASE_MIPS3D, 0,
OPTION_MIPS3D, OPTION_NO_MIPS3D,
2, 1, -1, -1 },
- { "mt", ASE_MT, 0,
+ { "mt", AFL_ASE_MT, 0,
OPTION_MT, OPTION_NO_MT,
2, 2, -1, -1 },
- { "smartmips", ASE_SMARTMIPS, 0,
+ { "smartmips", AFL_ASE_SMARTMIPS, 0,
OPTION_SMARTMIPS, OPTION_NO_SMARTMIPS,
1, -1, -1, -1 },
- { "virt", ASE_VIRT, ASE_VIRT64,
+ { "virt", AFL_ASE_VIRT, AFL_ASE_VIRT64,
OPTION_VIRT, OPTION_NO_VIRT,
2, 2, 2, 2 },
- { "msa", ASE_MSA, ASE_MSA64,
+ { "msa", AFL_ASE_MSA, AFL_ASE_MSA64,
OPTION_MSA, OPTION_NO_MSA,
2, 2, 2, 2 },
- { "xpa", ASE_XPA, 0,
+ { "xpa", AFL_ASE_XPA, 0,
OPTION_XPA, OPTION_NO_XPA,
2, 2, -1, -1 }
};
/* The set of ASEs that require -mfp64. */
-#define FP64_ASES (ASE_MIPS3D | ASE_MDMX)
+#define FP64_ASES (AFL_ASE_MIPS3D | AFL_ASE_MDMX)
/* Groups of ASE_* flags that represent different revisions of an ASE. */
static const unsigned int mips_ase_groups[] = {
- ASE_DSP | ASE_DSPR2
+ AFL_ASE_DSP | AFL_ASE_DSPR2
};
/* Pseudo-op table.
@@ -1660,6 +1678,7 @@ static const pseudo_typeS mips_pseudo_table[] =
{"cpadd", s_cpadd, 0},
{"insn", s_insn, 0},
{"nan", s_nan, 0},
+ {"module", s_module, 0},
/* Relatively generic pseudo-ops that happen to be used on MIPS
chips. */
@@ -1913,7 +1932,7 @@ mips_check_isa_supports_ase (const struct mips_ase *ase)
ase->name, base, size, min_rev);
}
if ((ase->flags & FP64_ASES)
- && mips_opts.fp32
+ && mips_opts.fp != 64
&& (warned_fp32 & ase->flags) != ase->flags)
{
warned_fp32 |= ase->flags;
@@ -1941,14 +1960,15 @@ mips_check_isa_supports_ases (void)
that were affected. */
static unsigned int
-mips_set_ase (const struct mips_ase *ase, bfd_boolean enabled_p)
+mips_set_ase (const struct mips_ase *ase, struct mips_set_options *opts,
+ bfd_boolean enabled_p)
{
unsigned int mask;
mask = mips_ase_mask (ase->flags);
- mips_opts.ase &= ~mask;
+ opts->ase &= ~mask;
if (enabled_p)
- mips_opts.ase |= ase->flags;
+ opts->ase |= ase->flags;
return mask;
}
@@ -3344,7 +3364,7 @@ md_begin (void)
g_switch_value = 0;
}
- if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_arch))
+ if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_opts.arch))
as_warn (_("could not set architecture and machine"));
op_hash = hash_new ();
@@ -3570,6 +3590,11 @@ md_begin (void)
}
}
+ sec = subseg_new (".MIPS.abiflags", (subsegT) 0);
+ bfd_set_section_flags (stdoutput, sec, flags);
+ bfd_set_section_alignment (stdoutput, sec, 3);
+ mips_flags_frag = frag_more (sizeof (Elf_External_ABIFlags_v0));
+
if (ECOFF_DEBUGGING)
{
sec = subseg_new (".mdebug", (subsegT) 0);
@@ -3602,6 +3627,173 @@ md_mips_end (void)
mips_emit_delays ();
if (! ECOFF_DEBUGGING)
md_obj_end ();
+
+ int fpabi = bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_GNU,
+ Tag_GNU_MIPS_ABI_FP);
+ switch (fpabi)
+ {
+ case Val_GNU_MIPS_ABI_FP_DOUBLE:
+ if ((file_mips_opts.gp32 ? 32 : 64) != file_mips_opts.fp
+ || file_mips_opts.single_float == 1
+ || file_mips_opts.soft_float == 1)
+ as_warn (_("Incorrect .gnu_attribute %d,%d found when module is "
+ "`%s'"),
+ Tag_GNU_MIPS_ABI_FP, fpabi,
+ (file_mips_opts.single_float == 1) ? "single-float"
+ : (file_mips_opts.soft_float == 1) ? "soft-float"
+ : (file_mips_opts.fp == 32) ? "fp32"
+ : (file_mips_opts.fp == 64) ? "fp64" : "fpxx");
+ break;
+ case Val_GNU_MIPS_ABI_FP_XX:
+ if (mips_abi != O32_ABI
+ || file_mips_opts.fp != 0
+ || file_mips_opts.single_float == 1
+ || file_mips_opts.soft_float == 1)
+ as_warn (_("Incorrect .gnu_attribute %d,%d found when module is "
+ "`%s'"),
+ Tag_GNU_MIPS_ABI_FP, fpabi,
+ (mips_abi != O32_ABI) ? "!-mabi=32"
+ : (file_mips_opts.single_float == 1) ? "single-float"
+ : (file_mips_opts.soft_float == 1) ? "soft-float"
+ : (file_mips_opts.fp == 32) ? "fp32"
+ : (file_mips_opts.fp == 64) ? "fp64" : "fpxx");
+ break;
+ case Val_GNU_MIPS_ABI_FP_64:
+ if (mips_abi != O32_ABI
+ || file_mips_opts.fp != 64
+ || file_mips_opts.single_float == 1
+ || file_mips_opts.soft_float == 1)
+ as_warn (_("Incorrect .gnu_attribute %d,%d found when module is "
+ "`%s'"),
+ Tag_GNU_MIPS_ABI_FP, fpabi,
+ (mips_abi != O32_ABI) ? "!-mabi=32"
+ : (file_mips_opts.single_float == 1) ? "single-float"
+ : (file_mips_opts.soft_float == 1) ? "soft-float"
+ : (file_mips_opts.fp == 32) ? "fp32"
+ : (file_mips_opts.fp == 64) ? "fp64" : "fpxx");
+ break;
+ case Val_GNU_MIPS_ABI_FP_SINGLE:
+ if (file_mips_opts.single_float != 1)
+ as_warn (_("Incorrect .gnu_attribute %d,%d found when module is "
+ "not `single-float'"),
+ Tag_GNU_MIPS_ABI_FP, fpabi);
+ break;
+ case Val_GNU_MIPS_ABI_FP_SOFT:
+ if (file_mips_opts.soft_float != 1)
+ as_warn (_("Incorrect .gnu_attribute %d,%d found when module is "
+ "not `soft-float'"),
+ Tag_GNU_MIPS_ABI_FP, fpabi);
+ break;
+ case Val_GNU_MIPS_ABI_FP_OLD_64:
+ as_warn (_("Incorrect .gnu_attribute %d,%d found. ABI not "
+ "supported"),
+ Tag_GNU_MIPS_ABI_FP, fpabi);
+ break;
+ default:
+ if (fpabi != Val_GNU_MIPS_ABI_FP_ANY)
+ as_warn (_("Incompatible module option and .gnu_attribute seen, "
+ "unexpected Tag_GNU_MIPS_ABI_FP: %d"),
+ fpabi);
+ break;
+ }
+
+ /* Only update the ABI if it is not already specified. A .gnu_attribute
+ always wins. */
+ if (fpabi == Val_GNU_MIPS_ABI_FP_ANY)
+ {
+ /* Soft-float gets precedence over single-float, the two options should
+ not be used together so this should not matter. */
+ if (file_mips_opts.soft_float == 1)
+ fpabi = Val_GNU_MIPS_ABI_FP_SOFT;
+ /* If floating-point code has been seen and the module is single-float
+ then give this precedence over the double-precision cases below.
+ Single-float can theoretically be used with any width register. */
+ else if (mips_seen_fp_code == TRUE
+ && file_mips_opts.single_float == 1)
+ fpabi = Val_GNU_MIPS_ABI_FP_SINGLE;
+ else if (mips_seen_fp_code == TRUE)
+ {
+ switch (file_mips_opts.fp)
+ {
+ case 32:
+ fpabi = Val_GNU_MIPS_ABI_FP_DOUBLE;
+ break;
+ case 0:
+ fpabi = Val_GNU_MIPS_ABI_FP_XX;
+ break;
+ case 64:
+ if (file_mips_opts.gp32)
+ fpabi = Val_GNU_MIPS_ABI_FP_64;
+ else
+ fpabi = Val_GNU_MIPS_ABI_FP_DOUBLE;
+ break;
+ }
+ }
+
+ bfd_elf_add_obj_attr_int (stdoutput, OBJ_ATTR_GNU,
+ Tag_GNU_MIPS_ABI_FP, fpabi);
+ }
+}
+
+/* Perform consistency checks on the current options. */
+
+static void
+mips_check_options (struct mips_set_options *opts, bfd_boolean abi_checks)
+{
+ /* Check the size of integer registers agrees with the ABI and ISA. */
+ if (opts->gp32 == 0 && !ISA_HAS_64BIT_REGS (opts->isa))
+ as_bad (_("`gp64' used with a 32-bit processor"));
+ else if (abi_checks == TRUE
+ && opts->gp32 == 1 && ABI_NEEDS_64BIT_REGS (mips_abi))
+ as_bad (_("`gp32' used with a 64-bit ABI"));
+ else if (abi_checks == TRUE
+ && opts->gp32 == 0 && ABI_NEEDS_32BIT_REGS (mips_abi))
+ as_bad (_("`gp64' used with a 32-bit ABI"));
+
+ /* Check the size of the float registers agrees with the ABI and ISA. */
+ switch (opts->fp)
+ {
+ case 0:
+ if (!CPU_HAS_LDC1_SDC1 (opts->arch))
+ as_bad (_("`fpxx' used with a cpu lacking ldc1/sdc1 instructions"));
+ else if (opts->single_float == 1
+ || opts->soft_float == 1)
+ as_bad (_("`fpxx' cannot be used with `single-float' or `soft-float'"));
+ break;
+ case 64:
+ if (!ISA_HAS_64BIT_FPRS (opts->isa))
+ as_bad (_("`fp64' used with a 32-bit fpu"));
+ else if (abi_checks == TRUE
+ && ABI_NEEDS_32BIT_REGS (mips_abi)
+ && !ISA_HAS_MXHC1 (opts->isa))
+ as_warn (_("`fp64' used with a 32-bit ABI"));
+ break;
+ case 32:
+ if (abi_checks == TRUE
+ && ABI_NEEDS_64BIT_REGS (mips_abi))
+ as_warn (_("`fp32' used with a 64-bit ABI"));
+ break;
+ default:
+ as_bad (_("Unknown size of floating point registers"));
+ }
+
+ if (opts->micromips == 1 && opts->mips16 == 1)
+ as_bad (_("`mips16' cannot be used with `micromips'"));
+}
+
+/* Perform consistency checks on the module level options exactly once.
+ This is a deferred check that happens:
+ at the first .set directive
+ or, at the first pseudo op that generates code
+ or, at the first instruction
+ or, at the end. */
+
+static void
+file_mips_check_options (void)
+{
+ if (file_mips_opts_checked == FALSE)
+ mips_check_options (&file_mips_opts, TRUE);
+ file_mips_opts_checked = TRUE;
}
void
@@ -3611,6 +3803,8 @@ md_assemble (char *str)
bfd_reloc_code_real_type unused_reloc[3]
= {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
+ file_mips_check_options ();
+
imm_expr.X_op = O_absent;
offset_expr.X_op = O_absent;
offset_reloc[0] = BFD_RELOC_UNUSED;
@@ -4397,7 +4591,7 @@ convert_reg_type (const struct mips_opcode *opcode,
case OP_REG_FP:
/* Allow vector register names for MDMX if the instruction is a 64-bit
FPR load, store or move (including moves to and from GPRs). */
- if ((mips_opts.ase & ASE_MDMX)
+ if ((mips_opts.ase & AFL_ASE_MDMX)
&& (opcode->pinfo & FP_D)
&& (opcode->pinfo & (INSN_COPROC_MOVE_DELAY
| INSN_COPROC_MEMORY_DELAY
@@ -4413,7 +4607,7 @@ convert_reg_type (const struct mips_opcode *opcode,
return RTYPE_CCC;
case OP_REG_VEC:
- if (opcode->membership & INSN_5400)
+ if (opcode->membership & AFL_EXT_5400)
return RTYPE_FPU;
return RTYPE_FPU | RTYPE_VEC;
@@ -4464,11 +4658,22 @@ check_regno (struct mips_arg_info *arg,
if (AT && type == OP_REG_GP && regno == AT)
arg->seen_at = TRUE;
- if (type == OP_REG_FP
- && (regno & 1) != 0
- && HAVE_32BIT_FPRS
- && !mips_oddfpreg_ok (arg->insn->insn_mo, arg->opnum))
- as_warn (_("float register should be even, was %d"), regno);
+ if (type == OP_REG_FP)
+ {
+ mips_seen_fp_code = TRUE;
+ if ((regno & 1) != 0)
+ {
+ if (mips_opts.mips_defer_fp_warn == TRUE)
+ as_warn (_("Dangerous use of FP registers in fp%s when module is fp%s"),
+ (mips_opts.fp == 32) ? "32"
+ : (mips_opts.fp == 64) ? "64" : "xx",
+ (file_mips_opts.fp == 32) ? "32"
+ : (file_mips_opts.fp == 64) ? "64" : "xx");
+ if (HAVE_32BIT_FPRS
+ && !mips_oddfpreg_ok (arg->insn->insn_mo, arg->opnum))
+ as_warn (_("float register should be even, was %d"), regno);
+ }
+ }
if (type == OP_REG_CCC)
{
@@ -5123,7 +5328,7 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
if (arg->token->type == OT_REG)
{
- if ((opcode->membership & INSN_5400)
+ if ((opcode->membership & AFL_EXT_5400)
&& strcmp (opcode->name, "rzu.ob") == 0)
{
set_insn_error_i (arg->argnum, _("operand %d must be an immediate"),
@@ -5150,7 +5355,7 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
else
{
/* A full vector. */
- if ((opcode->membership & INSN_5400)
+ if ((opcode->membership & AFL_EXT_5400)
&& (strcmp (opcode->name, "sll.ob") == 0
|| strcmp (opcode->name, "srl.ob") == 0))
{
@@ -5322,13 +5527,12 @@ match_float_constant (struct mips_arg_info *arg, expressionS *imm,
/* Handle 64-bit constants for which an immediate value is best. */
if (length == 8
&& !mips_disable_float_construction
- /* Constants can only be constructed in GPRs and copied
- to FPRs if the GPRs are at least as wide as the FPRs.
- Force the constant into memory if we are using 64-bit FPRs
- but the GPRs are only 32 bits wide. */
- /* ??? No longer true with the addition of MTHC1, but this
- is legacy code... */
- && (using_gprs || !(HAVE_64BIT_FPRS && HAVE_32BIT_GPRS))
+ /* Constants can only be constructed in GPRs and copied to FPRs if the
+ GPRs are at least as wide as the FPRs or MTHC1 is available. */
+ && (using_gprs
+ || HAVE_64BIT_GPRS
+ || ISA_HAS_MXHC1 (mips_opts.isa)
+ || (HAVE_32BIT_FPRS && mips_opts.fp != 0))
&& ((data[0] == 0 && data[1] == 0)
|| (data[2] == 0 && data[3] == 0))
&& ((data[4] == 0 && data[5] == 0)
@@ -6690,7 +6894,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
&& (mips_opts.at || mips_pic == NO_PIC)
/* Don't relax BPOSGE32/64 or BC1ANY2T/F and BC1ANY4T/F
as they have no complementing branches. */
- && !(ip->insn_mo->ase & (ASE_MIPS3D | ASE_DSP64 | ASE_DSP)));
+ && !(ip->insn_mo->ase & (AFL_ASE_MIPS3D | AFL_ASE_DSP64
+ | AFL_ASE_DSP)));
if (!HAVE_CODE_COMPRESSION
&& address_expr
@@ -11520,14 +11725,18 @@ macro (struct mips_cl_insn *ip, char *str)
{
used_at = 1;
load_register (AT, &imm_expr, HAVE_64BIT_FPRS);
- if (HAVE_64BIT_FPRS)
- {
- gas_assert (HAVE_64BIT_GPRS);
- macro_build (NULL, "dmtc1", "t,S", AT, op[0]);
- }
+ if (HAVE_64BIT_FPRS && HAVE_64BIT_GPRS)
+ macro_build (NULL, "dmtc1", "t,S", AT, op[0]);
else
{
- macro_build (NULL, "mtc1", "t,G", AT, op[0] + 1);
+ if (ISA_HAS_MXHC1 (mips_opts.isa))
+ macro_build (NULL, "mthc1", "t,G", AT, op[0]);
+ else if (mips_opts.fp != 32)
+ as_bad (_("Unable to generate `%s' compliant code "
+ "without mthc1"),
+ (mips_opts.fp == 64) ? "fp64" : "fpxx");
+ else
+ macro_build (NULL, "mtc1", "t,G", AT, op[0] + 1);
if (offset_expr.X_op == O_absent)
macro_build (NULL, "mtc1", "t,G", 0, op[0]);
else
@@ -13456,7 +13665,7 @@ md_parse_option (int c, char *arg)
for (i = 0; i < ARRAY_SIZE (mips_ases); i++)
if (c == mips_ases[i].option_on || c == mips_ases[i].option_off)
{
- file_ase_explicit |= mips_set_ase (&mips_ases[i],
+ file_ase_explicit |= mips_set_ase (&mips_ases[i], &file_mips_opts,
c == mips_ases[i].option_on);
return 1;
}
@@ -13506,39 +13715,39 @@ md_parse_option (int c, char *arg)
break;
case OPTION_MIPS1:
- file_mips_isa = ISA_MIPS1;
+ file_mips_opts.isa = ISA_MIPS1;
break;
case OPTION_MIPS2:
- file_mips_isa = ISA_MIPS2;
+ file_mips_opts.isa = ISA_MIPS2;
break;
case OPTION_MIPS3:
- file_mips_isa = ISA_MIPS3;
+ file_mips_opts.isa = ISA_MIPS3;
break;
case OPTION_MIPS4:
- file_mips_isa = ISA_MIPS4;
+ file_mips_opts.isa = ISA_MIPS4;
break;
case OPTION_MIPS5:
- file_mips_isa = ISA_MIPS5;
+ file_mips_opts.isa = ISA_MIPS5;
break;
case OPTION_MIPS32:
- file_mips_isa = ISA_MIPS32;
+ file_mips_opts.isa = ISA_MIPS32;
break;
case OPTION_MIPS32R2:
- file_mips_isa = ISA_MIPS32R2;
+ file_mips_opts.isa = ISA_MIPS32R2;
break;
case OPTION_MIPS64R2:
- file_mips_isa = ISA_MIPS64R2;
+ file_mips_opts.isa = ISA_MIPS64R2;
break;
case OPTION_MIPS64:
- file_mips_isa = ISA_MIPS64;
+ file_mips_opts.isa = ISA_MIPS64;
break;
case OPTION_MTUNE:
@@ -13582,32 +13791,32 @@ md_parse_option (int c, char *arg)
break;
case OPTION_MICROMIPS:
- if (mips_opts.mips16 == 1)
+ if (file_mips_opts.mips16 == 1)
{
as_bad (_("-mmicromips cannot be used with -mips16"));
return 0;
}
- mips_opts.micromips = 1;
+ file_mips_opts.micromips = 1;
mips_no_prev_insn ();
break;
case OPTION_NO_MICROMIPS:
- mips_opts.micromips = 0;
+ file_mips_opts.micromips = 0;
mips_no_prev_insn ();
break;
case OPTION_MIPS16:
- if (mips_opts.micromips == 1)
+ if (file_mips_opts.micromips == 1)
{
as_bad (_("-mips16 cannot be used with -micromips"));
return 0;
}
- mips_opts.mips16 = 1;
+ file_mips_opts.mips16 = 1;
mips_no_prev_insn ();
break;
case OPTION_NO_MIPS16:
- mips_opts.mips16 = 0;
+ file_mips_opts.mips16 = 0;
mips_no_prev_insn ();
break;
@@ -13676,11 +13885,11 @@ md_parse_option (int c, char *arg)
break;
case OPTION_INSN32:
- mips_opts.insn32 = TRUE;
+ file_mips_opts.insn32 = TRUE;
break;
case OPTION_NO_INSN32:
- mips_opts.insn32 = FALSE;
+ file_mips_opts.insn32 = FALSE;
break;
case OPTION_MSHARED:
@@ -13692,11 +13901,11 @@ md_parse_option (int c, char *arg)
break;
case OPTION_MSYM32:
- mips_opts.sym32 = TRUE;
+ file_mips_opts.sym32 = TRUE;
break;
case OPTION_MNO_SYM32:
- mips_opts.sym32 = FALSE;
+ file_mips_opts.sym32 = FALSE;
break;
/* When generating ELF code, we permit -KPIC and -call_shared to
@@ -13746,35 +13955,39 @@ md_parse_option (int c, char *arg)
break;
case OPTION_GP32:
- file_mips_gp32 = 1;
+ file_mips_opts.gp32 = 1;
break;
case OPTION_GP64:
- file_mips_gp32 = 0;
+ file_mips_opts.gp32 = 0;
break;
case OPTION_FP32:
- file_mips_fp32 = 1;
+ file_mips_opts.fp = 32;
+ break;
+
+ case OPTION_FPXX:
+ file_mips_opts.fp = 0;
break;
case OPTION_FP64:
- file_mips_fp32 = 0;
+ file_mips_opts.fp = 64;
break;
case OPTION_SINGLE_FLOAT:
- file_mips_single_float = 1;
+ file_mips_opts.single_float = 1;
break;
case OPTION_DOUBLE_FLOAT:
- file_mips_single_float = 0;
+ file_mips_opts.single_float = 0;
break;
case OPTION_SOFT_FLOAT:
- file_mips_soft_float = 1;
+ file_mips_opts.soft_float = 1;
break;
case OPTION_HARD_FLOAT:
- file_mips_soft_float = 0;
+ file_mips_opts.soft_float = 0;
break;
case OPTION_MABI:
@@ -13849,22 +14062,7 @@ md_parse_option (int c, char *arg)
return 1;
}
-/* Set up globals to generate code for the ISA or processor
- described by INFO. */
-
-static void
-mips_set_architecture (const struct mips_cpu_info *info)
-{
- if (info != 0)
- {
- file_mips_arch = info->cpu;
- mips_opts.arch = info->cpu;
- mips_opts.isa = info->isa;
- }
-}
-
-
-/* Likewise for tuning. */
+/* Set up globals to tune for the ISA or processor described by INFO. */
static void
mips_set_tune (const struct mips_cpu_info *info)
@@ -13899,9 +14097,9 @@ mips_after_parse_args (void)
if (mips_arch_string != 0)
arch_info = mips_parse_cpu ("-march", mips_arch_string);
- if (file_mips_isa != ISA_UNKNOWN)
+ if (file_mips_opts.isa != ISA_UNKNOWN)
{
- /* Handle -mipsN. At this point, file_mips_isa contains the
+ /* Handle -mipsN. At this point, file_mips_opts.isa contains the
ISA level specified by -mipsN, while arch_info->isa contains
the -march selection (if any). */
if (arch_info != 0)
@@ -13909,14 +14107,14 @@ mips_after_parse_args (void)
/* -march takes precedence over -mipsN, since it is more descriptive.
There's no harm in specifying both as long as the ISA levels
are the same. */
- if (file_mips_isa != arch_info->isa)
+ if (file_mips_opts.isa != arch_info->isa)
as_bad (_("-%s conflicts with the other architecture options,"
" which imply -%s"),
- mips_cpu_info_from_isa (file_mips_isa)->name,
+ mips_cpu_info_from_isa (file_mips_opts.isa)->name,
mips_cpu_info_from_isa (arch_info->isa)->name);
}
else
- arch_info = mips_cpu_info_from_isa (file_mips_isa);
+ arch_info = mips_cpu_info_from_isa (file_mips_opts.isa);
}
if (arch_info == 0)
@@ -13929,9 +14127,11 @@ mips_after_parse_args (void)
as_bad (_("-march=%s is not compatible with the selected ABI"),
arch_info->name);
- mips_set_architecture (arch_info);
+ file_mips_opts.arch = arch_info->cpu;
+ file_mips_opts.isa = arch_info->isa;
- /* Optimize for file_mips_arch, unless -mtune selects a different processor. */
+ /* Optimize for file_mips_opts.arch, unless -mtune selects a different
+ processor. */
if (mips_tune_string != 0)
tune_info = mips_parse_cpu ("-mtune", mips_tune_string);
@@ -13940,30 +14140,17 @@ mips_after_parse_args (void)
else
mips_set_tune (tune_info);
- if (file_mips_gp32 >= 0)
- {
- /* The user specified the size of the integer registers. Make sure
- it agrees with the ABI and ISA. */
- if (file_mips_gp32 == 0 && !ISA_HAS_64BIT_REGS (mips_opts.isa))
- as_bad (_("-mgp64 used with a 32-bit processor"));
- else if (file_mips_gp32 == 1 && ABI_NEEDS_64BIT_REGS (mips_abi))
- as_bad (_("-mgp32 used with a 64-bit ABI"));
- else if (file_mips_gp32 == 0 && ABI_NEEDS_32BIT_REGS (mips_abi))
- as_bad (_("-mgp64 used with a 32-bit ABI"));
- }
- else
+ if (file_mips_opts.gp32 < 0)
{
/* Infer the integer register size from the ABI and processor.
Restrict ourselves to 32-bit registers if that's all the
processor has, or if the ABI cannot handle 64-bit registers. */
- file_mips_gp32 = (ABI_NEEDS_32BIT_REGS (mips_abi)
- || !ISA_HAS_64BIT_REGS (mips_opts.isa));
+ file_mips_opts.gp32 = (ABI_NEEDS_32BIT_REGS (mips_abi)
+ || !ISA_HAS_64BIT_REGS (file_mips_opts.isa));
}
- switch (file_mips_fp32)
+ if (file_mips_opts.fp < 0)
{
- default:
- case -1:
/* No user specified float register size.
??? GAS treats single-float processors as though they had 64-bit
float registers (although it complains when double-precision
@@ -13971,67 +14158,49 @@ mips_after_parse_args (void)
registers would lead to spurious "register must be even" messages.
So here we assume float registers are never smaller than the
integer ones. */
- if (file_mips_gp32 == 0)
+ if (file_mips_opts.gp32 == 0)
/* 64-bit integer registers implies 64-bit float registers. */
- file_mips_fp32 = 0;
- else if ((mips_opts.ase & FP64_ASES)
- && ISA_HAS_64BIT_FPRS (mips_opts.isa))
+ file_mips_opts.fp = 64;
+ else if ((file_mips_opts.ase & FP64_ASES)
+ && ISA_HAS_64BIT_FPRS (file_mips_opts.isa))
/* -mips3d and -mdmx imply 64-bit float registers, if possible. */
- file_mips_fp32 = 0;
+ file_mips_opts.fp = 64;
else
/* 32-bit float registers. */
- file_mips_fp32 = 1;
- break;
-
- /* The user specified the size of the float registers. Check if it
- agrees with the ABI and ISA. */
- case 0:
- if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
- as_bad (_("-mfp64 used with a 32-bit fpu"));
- else if (ABI_NEEDS_32BIT_REGS (mips_abi)
- && !ISA_HAS_MXHC1 (mips_opts.isa))
- as_warn (_("-mfp64 used with a 32-bit ABI"));
- break;
- case 1:
- if (ABI_NEEDS_64BIT_REGS (mips_abi))
- as_warn (_("-mfp32 used with a 64-bit ABI"));
- break;
+ file_mips_opts.fp = 32;
}
/* End of GCC-shared inference code. */
/* This flag is set when we have a 64-bit capable CPU but use only
32-bit wide registers. Note that EABI does not use it. */
- if (ISA_HAS_64BIT_REGS (mips_opts.isa)
- && ((mips_abi == NO_ABI && file_mips_gp32 == 1)
+ if (ISA_HAS_64BIT_REGS (file_mips_opts.isa)
+ && ((mips_abi == NO_ABI && file_mips_opts.gp32 == 1)
|| mips_abi == O32_ABI))
mips_32bitmode = 1;
- if (mips_opts.isa == ISA_MIPS1 && mips_trap)
+ if (file_mips_opts.isa == ISA_MIPS1 && mips_trap)
as_bad (_("trap exception not supported at ISA 1"));
/* If the selected architecture includes support for ASEs, enable
generation of code for them. */
- if (mips_opts.mips16 == -1)
- mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_arch)) ? 1 : 0;
- if (mips_opts.micromips == -1)
- mips_opts.micromips = (CPU_HAS_MICROMIPS (file_mips_arch)) ? 1 : 0;
+ if (file_mips_opts.mips16 == -1)
+ file_mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_opts.arch)) ? 1 : 0;
+ if (file_mips_opts.micromips == -1)
+ file_mips_opts.micromips = (CPU_HAS_MICROMIPS (file_mips_opts.arch))
+ ? 1 : 0;
/* MIPS3D and MDMX require 64-bit FPRs, so -mfp32 should stop those
ASEs from being selected implicitly. */
- if (file_mips_fp32 == 1)
- file_ase_explicit |= ASE_MIPS3D | ASE_MDMX;
+ if (file_mips_opts.fp == 32)
+ file_ase_explicit |= AFL_ASE_MIPS3D | AFL_ASE_MDMX;
/* If the user didn't explicitly select or deselect a particular ASE,
use the default setting for the CPU. */
- mips_opts.ase |= (arch_info->ase & ~file_ase_explicit);
+ file_mips_opts.ase |= (arch_info->ase & ~file_ase_explicit);
- file_mips_isa = mips_opts.isa;
- file_ase = mips_opts.ase;
- mips_opts.gp32 = file_mips_gp32;
- mips_opts.fp32 = file_mips_fp32;
- mips_opts.soft_float = file_mips_soft_float;
- mips_opts.single_float = file_mips_single_float;
+ /* Set up the current options. These may change throughout assembly. */
+ mips_opts = file_mips_opts;
mips_check_isa_supports_ases ();
@@ -14922,30 +15091,11 @@ struct mips_option_stack
static struct mips_option_stack *mips_opts_stack;
-/* Handle the .set pseudo-op. */
-
-static void
-s_mipsset (int x ATTRIBUTE_UNUSED)
+static bfd_boolean
+s_mipssettings (char * name)
{
- char *name = input_line_pointer, ch;
const struct mips_ase *ase;
-
- while (!is_end_of_line[(unsigned char) *input_line_pointer])
- ++input_line_pointer;
- ch = *input_line_pointer;
- *input_line_pointer = '\0';
-
- if (strcmp (name, "reorder") == 0)
- {
- if (mips_opts.noreorder)
- end_noreorder ();
- }
- else if (strcmp (name, "noreorder") == 0)
- {
- if (!mips_opts.noreorder)
- start_noreorder ();
- }
- else if (strncmp (name, "at=", 3) == 0)
+ if (strncmp (name, "at=", 3) == 0)
{
char *s = name + 3;
@@ -14953,61 +15103,27 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
as_bad (_("unrecognized register name `%s'"), s);
}
else if (strcmp (name, "at") == 0)
- {
- mips_opts.at = ATREG;
- }
+ mips_opts.at = ATREG;
else if (strcmp (name, "noat") == 0)
- {
- mips_opts.at = ZERO;
- }
- else if (strcmp (name, "macro") == 0)
- {
- mips_opts.warn_about_macros = 0;
- }
- else if (strcmp (name, "nomacro") == 0)
- {
- if (mips_opts.noreorder == 0)
- as_bad (_("`noreorder' must be set before `nomacro'"));
- mips_opts.warn_about_macros = 1;
- }
+ mips_opts.at = ZERO;
else if (strcmp (name, "move") == 0 || strcmp (name, "novolatile") == 0)
- {
- mips_opts.nomove = 0;
- }
+ mips_opts.nomove = 0;
else if (strcmp (name, "nomove") == 0 || strcmp (name, "volatile") == 0)
- {
- mips_opts.nomove = 1;
- }
+ mips_opts.nomove = 1;
else if (strcmp (name, "bopt") == 0)
- {
- mips_opts.nobopt = 0;
- }
+ mips_opts.nobopt = 0;
else if (strcmp (name, "nobopt") == 0)
- {
- mips_opts.nobopt = 1;
- }
- else if (strcmp (name, "gp=default") == 0)
- mips_opts.gp32 = file_mips_gp32;
+ mips_opts.nobopt = 1;
else if (strcmp (name, "gp=32") == 0)
mips_opts.gp32 = 1;
else if (strcmp (name, "gp=64") == 0)
- {
- if (!ISA_HAS_64BIT_REGS (mips_opts.isa))
- as_warn (_("%s isa does not support 64-bit registers"),
- mips_cpu_info_from_isa (mips_opts.isa)->name);
- mips_opts.gp32 = 0;
- }
- else if (strcmp (name, "fp=default") == 0)
- mips_opts.fp32 = file_mips_fp32;
+ mips_opts.gp32 = 0;
else if (strcmp (name, "fp=32") == 0)
- mips_opts.fp32 = 1;
+ mips_opts.fp = 32;
+ else if (strcmp (name, "fp=xx") == 0)
+ mips_opts.fp = 0;
else if (strcmp (name, "fp=64") == 0)
- {
- if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
- as_warn (_("%s isa does not support 64-bit floating point registers"),
- mips_cpu_info_from_isa (mips_opts.isa)->name);
- mips_opts.fp32 = 0;
- }
+ mips_opts.fp = 64;
else if (strcmp (name, "softfloat") == 0)
mips_opts.soft_float = 1;
else if (strcmp (name, "hardfloat") == 0)
@@ -15018,45 +15134,29 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
mips_opts.single_float = 0;
else if (strcmp (name, "mips16") == 0
|| strcmp (name, "MIPS-16") == 0)
- {
- if (mips_opts.micromips == 1)
- as_fatal (_("`mips16' cannot be used with `micromips'"));
- mips_opts.mips16 = 1;
- }
+ mips_opts.mips16 = 1;
else if (strcmp (name, "nomips16") == 0
|| strcmp (name, "noMIPS-16") == 0)
mips_opts.mips16 = 0;
else if (strcmp (name, "micromips") == 0)
- {
- if (mips_opts.mips16 == 1)
- as_fatal (_("`micromips' cannot be used with `mips16'"));
- mips_opts.micromips = 1;
- }
+ mips_opts.micromips = 1;
else if (strcmp (name, "nomicromips") == 0)
mips_opts.micromips = 0;
else if (name[0] == 'n'
&& name[1] == 'o'
&& (ase = mips_lookup_ase (name + 2)))
- mips_set_ase (ase, FALSE);
+ mips_set_ase (ase, &mips_opts, FALSE);
else if ((ase = mips_lookup_ase (name)))
- mips_set_ase (ase, TRUE);
+ mips_set_ase (ase, &mips_opts, TRUE);
else if (strncmp (name, "mips", 4) == 0 || strncmp (name, "arch=", 5) == 0)
{
- int reset = 0;
-
/* Permit the user to change the ISA and architecture on the fly.
Needless to say, misuse can cause serious problems. */
- if (strcmp (name, "mips0") == 0 || strcmp (name, "arch=default") == 0)
- {
- reset = 1;
- mips_opts.isa = file_mips_isa;
- mips_opts.arch = file_mips_arch;
- }
- else if (strncmp (name, "arch=", 5) == 0)
+ if (strncmp (name, "arch=", 5) == 0)
{
const struct mips_cpu_info *p;
- p = mips_parse_cpu("internal use", name + 5);
+ p = mips_parse_cpu ("internal use", name + 5);
if (!p)
as_bad (_("unknown architecture %s"), name + 5);
else
@@ -15069,7 +15169,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
{
const struct mips_cpu_info *p;
- p = mips_parse_cpu("internal use", name);
+ p = mips_parse_cpu ("internal use", name);
if (!p)
as_bad (_("unknown ISA level %s"), name + 4);
else
@@ -15080,42 +15180,6 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
}
else
as_bad (_("unknown ISA or architecture %s"), name);
-
- switch (mips_opts.isa)
- {
- case 0:
- break;
- case ISA_MIPS1:
- case ISA_MIPS2:
- case ISA_MIPS32:
- case ISA_MIPS32R2:
- mips_opts.gp32 = 1;
- mips_opts.fp32 = 1;
- break;
- case ISA_MIPS3:
- case ISA_MIPS4:
- case ISA_MIPS5:
- case ISA_MIPS64:
- case ISA_MIPS64R2:
- mips_opts.gp32 = 0;
- if (mips_opts.arch == CPU_R5900)
- {
- mips_opts.fp32 = 1;
- }
- else
- {
- mips_opts.fp32 = 0;
- }
- break;
- default:
- as_bad (_("unknown ISA level %s"), name + 4);
- break;
- }
- if (reset)
- {
- mips_opts.gp32 = file_mips_gp32;
- mips_opts.fp32 = file_mips_fp32;
- }
}
else if (strcmp (name, "autoextend") == 0)
mips_opts.noautoextend = 0;
@@ -15125,6 +15189,68 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
mips_opts.insn32 = TRUE;
else if (strcmp (name, "noinsn32") == 0)
mips_opts.insn32 = FALSE;
+ else if (strcmp (name, "sym32") == 0)
+ mips_opts.sym32 = TRUE;
+ else if (strcmp (name, "nosym32") == 0)
+ mips_opts.sym32 = FALSE;
+ else
+ return FALSE;
+ return TRUE;
+}
+
+/* Handle the .set pseudo-op. */
+
+static void
+s_mipsset (int x ATTRIBUTE_UNUSED)
+{
+ char *name = input_line_pointer, ch;
+ int prev_isa = mips_opts.isa;
+
+ file_mips_check_options ();
+
+ while (!is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ ch = *input_line_pointer;
+ *input_line_pointer = '\0';
+
+ if (strchr (name, ','))
+ {
+ /* Generic ".set" directive; use the generic handler. */
+ *input_line_pointer = ch;
+ input_line_pointer = name;
+ s_set (0);
+ return;
+ }
+
+ if (strcmp (name, "reorder") == 0)
+ {
+ if (mips_opts.noreorder)
+ end_noreorder ();
+ }
+ else if (strcmp (name, "noreorder") == 0)
+ {
+ if (!mips_opts.noreorder)
+ start_noreorder ();
+ }
+ else if (strcmp (name, "macro") == 0)
+ mips_opts.warn_about_macros = 0;
+ else if (strcmp (name, "nomacro") == 0)
+ {
+ if (mips_opts.noreorder == 0)
+ as_bad (_("`noreorder' must be set before `nomacro'"));
+ mips_opts.warn_about_macros = 1;
+ }
+ else if (strcmp (name, "gp=default") == 0)
+ mips_opts.gp32 = file_mips_opts.gp32;
+ else if (strcmp (name, "fp=default") == 0)
+ mips_opts.fp = file_mips_opts.fp;
+ else if (strcmp (name, "mips0") == 0 || strcmp (name, "arch=default") == 0)
+ {
+ mips_opts.isa = file_mips_opts.isa;
+ mips_opts.arch = file_mips_opts.arch;
+ mips_opts.gp32 = file_mips_opts.gp32;
+ mips_opts.fp = file_mips_opts.fp;
+ }
else if (strcmp (name, "push") == 0)
{
struct mips_option_stack *s;
@@ -15155,23 +15281,87 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
free (s);
}
}
- else if (strcmp (name, "sym32") == 0)
- mips_opts.sym32 = TRUE;
- else if (strcmp (name, "nosym32") == 0)
- mips_opts.sym32 = FALSE;
- else if (strchr (name, ','))
+ else if (s_mipssettings (name) == FALSE)
+ as_warn (_("tried to set unrecognized symbol: %s\n"), name);
+
+ /* The use of .set [arch|cpu]= historically 'fixes' the width of gp and fp
+ registers based on what is supported by the arch/cpu. */
+ if (mips_opts.isa != prev_isa)
{
- /* Generic ".set" directive; use the generic handler. */
- *input_line_pointer = ch;
- input_line_pointer = name;
- s_set (0);
- return;
+ switch (mips_opts.isa)
+ {
+ case 0:
+ break;
+ case ISA_MIPS1:
+ case ISA_MIPS2:
+ case ISA_MIPS32:
+ case ISA_MIPS32R2:
+ mips_opts.gp32 = 1;
+ if (mips_opts.fp != 0)
+ mips_opts.fp = 32;
+ break;
+ case ISA_MIPS3:
+ case ISA_MIPS4:
+ case ISA_MIPS5:
+ case ISA_MIPS64:
+ case ISA_MIPS64R2:
+ mips_opts.gp32 = 0;
+ if (mips_opts.arch == CPU_R5900)
+ {
+ if (mips_opts.fp != 0)
+ mips_opts.fp = 32;
+ }
+ else if (mips_opts.fp != 0)
+ mips_opts.fp = 64;
+ break;
+ default:
+ as_bad (_("unknown ISA level %s"), name + 4);
+ break;
+ }
}
- else
+
+ mips_check_options (&mips_opts, FALSE);
+
+ /* An error may occur if entering fp32 with the overall module as fp64
+ and vice-versa. Record incompatibilities to report dangerous code
+ generation if it occurs. */
+ mips_opts.mips_defer_fp_warn = (mips_abi == O32_ABI
+ && file_mips_opts.fp != 0 && mips_opts.fp != 0
+ && mips_opts.fp != file_mips_opts.fp);
+
+ mips_check_isa_supports_ases ();
+ *input_line_pointer = ch;
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the .module pseudo-op. */
+
+static void
+s_module (int ignore ATTRIBUTE_UNUSED)
+{
+ char *name = input_line_pointer, ch;
+ int prev_arch = file_mips_opts.arch;
+
+ while (!is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ ch = *input_line_pointer;
+ *input_line_pointer = '\0';
+
+ if (file_mips_opts_checked == FALSE)
{
- as_warn (_("tried to set unrecognized symbol: %s\n"), name);
+ if (s_mipssettings (name) == FALSE)
+ as_warn (_(".module used with unrecognized symbol: %s\n"), name);
+
+ /* Update module level settings from mips_opts. */
+ file_mips_opts = mips_opts;
}
- mips_check_isa_supports_ases ();
+ else
+ as_warn (_("ignoring .module after generating code"));
+
+ if (prev_arch != file_mips_opts.arch
+ && ! bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_opts.arch))
+ as_warn (_("could not set architecture and machine"));
+
*input_line_pointer = ch;
demand_empty_rest_of_line ();
}
@@ -15218,6 +15408,8 @@ s_cpload (int ignore ATTRIBUTE_UNUSED)
int reg;
int in_shared;
+ file_mips_check_options ();
+
/* If we are not generating SVR4 PIC code, or if this is NewABI code,
.cpload is ignored. */
if (mips_pic != SVR4_PIC || HAVE_NEWABI)
@@ -15295,6 +15487,8 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
expressionS ex_sym;
int reg1;
+ file_mips_check_options ();
+
/* If we are not generating SVR4 PIC code, .cpsetup is ignored.
We also need NewABI support. */
if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
@@ -15398,6 +15592,8 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
static void
s_cplocal (int ignore ATTRIBUTE_UNUSED)
{
+ file_mips_check_options ();
+
/* If we are not generating SVR4 PIC code, or if this is not NewABI code,
.cplocal is ignored. */
if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
@@ -15426,6 +15622,8 @@ s_cprestore (int ignore ATTRIBUTE_UNUSED)
{
expressionS ex;
+ file_mips_check_options ();
+
/* If we are not generating SVR4 PIC code, or if this is NewABI code,
.cprestore is ignored. */
if (mips_pic != SVR4_PIC || HAVE_NEWABI)
@@ -15473,6 +15671,8 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED)
{
expressionS ex;
+ file_mips_check_options ();
+
/* If we are not generating SVR4 PIC code, .cpreturn is ignored.
We also need NewABI support. */
if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
@@ -15707,6 +15907,8 @@ s_cpadd (int ignore ATTRIBUTE_UNUSED)
{
int reg;
+ file_mips_check_options ();
+
/* This is ignored when not generating SVR4 PIC code. */
if (mips_pic != SVR4_PIC)
{
@@ -17277,6 +17479,67 @@ mips_add_dot_label (symbolS *sym)
void
mips_elf_final_processing (void)
{
+ int fpabi;
+ Elf_Internal_ABIFlags_v0 flags;
+
+ flags.version = 0;
+ flags.isa_rev = 0;
+ switch (file_mips_opts.isa)
+ {
+ case INSN_ISA1:
+ flags.isa_level = 1;
+ break;
+ case INSN_ISA2:
+ flags.isa_level = 2;
+ break;
+ case INSN_ISA3:
+ flags.isa_level = 3;
+ break;
+ case INSN_ISA4:
+ flags.isa_level = 4;
+ break;
+ case INSN_ISA5:
+ flags.isa_level = 5;
+ break;
+ case INSN_ISA32:
+ flags.isa_level = 32;
+ flags.isa_rev = 1;
+ break;
+ case INSN_ISA32R2:
+ flags.isa_level = 32;
+ flags.isa_rev = 2;
+ break;
+ case INSN_ISA64:
+ flags.isa_level = 64;
+ flags.isa_rev = 1;
+ break;
+ case INSN_ISA64R2:
+ flags.isa_level = 64;
+ flags.isa_rev = 2;
+ break;
+ }
+
+ flags.gpr_size = file_mips_opts.gp32 ? AFL_REG_32 : AFL_REG_64;
+ flags.cpr1_size = file_mips_opts.soft_float ? AFL_REG_NONE
+ : (file_mips_opts.ase & AFL_ASE_MSA) ? AFL_REG_128
+ : (file_mips_opts.fp == 64) ? AFL_REG_64
+ : AFL_REG_32;
+ flags.cpr2_size = AFL_REG_NONE;
+ flags.fp_abi = bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_GNU,
+ Tag_GNU_MIPS_ABI_FP);
+ flags.isa_ext = cpu_insn_mask (file_mips_opts.arch);
+ flags.ases = file_mips_opts.ase;
+ if (file_ase_mips16)
+ flags.ases |= AFL_ASE_MIPS16;
+ if (file_ase_micromips)
+ flags.ases |= AFL_ASE_MICROMIPS;
+ flags.flags1 = 0;
+ flags.flags2 = 0;
+
+ bfd_mips_elf_swap_abiflags_v0_out (stdoutput, &flags,
+ ((Elf_External_ABIFlags_v0 *)
+ mips_flags_frag));
+
/* Write out the register information. */
if (mips_abi != N64_ABI)
{
@@ -17328,7 +17591,7 @@ mips_elf_final_processing (void)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
if (file_ase_micromips)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MICROMIPS;
- if (file_ase & ASE_MDMX)
+ if (file_ase & AFL_ASE_MDMX)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MDMX;
/* Set the MIPS ELF ABI flags. */
@@ -17338,7 +17601,7 @@ mips_elf_final_processing (void)
elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_O64;
else if (mips_abi == EABI_ABI)
{
- if (!file_mips_gp32)
+ if (!file_mips_opts.gp32)
elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI64;
else
elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI32;
@@ -17355,7 +17618,9 @@ mips_elf_final_processing (void)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_NAN2008;
/* 32 bit code with 64 bit FP registers. */
- if (!file_mips_fp32 && ABI_NEEDS_32BIT_REGS (mips_abi))
+ fpabi = bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_GNU,
+ Tag_GNU_MIPS_ABI_FP);
+ if (fpabi == Val_GNU_MIPS_ABI_FP_OLD_64)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_FP64;
}
@@ -17470,6 +17735,9 @@ md_obj_end (void)
/* Check for premature end, nesting errors, etc. */
if (cur_proc_ptr)
as_warn (_("missing .end at end of assembly"));
+
+ /* Just in case no code was emitted, do the consistency check. */
+ file_mips_check_options ();
}
static long
@@ -17856,20 +18124,20 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
{ "4kc", 0, 0, ISA_MIPS32, CPU_MIPS32 },
{ "4km", 0, 0, ISA_MIPS32, CPU_MIPS32 },
{ "4kp", 0, 0, ISA_MIPS32, CPU_MIPS32 },
- { "4ksc", 0, ASE_SMARTMIPS, ISA_MIPS32, CPU_MIPS32 },
+ { "4ksc", 0, AFL_ASE_SMARTMIPS, ISA_MIPS32, CPU_MIPS32 },
/* MIPS 32 Release 2 */
{ "4kec", 0, 0, ISA_MIPS32R2, CPU_MIPS32R2 },
{ "4kem", 0, 0, ISA_MIPS32R2, CPU_MIPS32R2 },
{ "4kep", 0, 0, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "4ksd", 0, ASE_SMARTMIPS, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "4ksd", 0, AFL_ASE_SMARTMIPS, ISA_MIPS32R2, CPU_MIPS32R2 },
{ "m4k", 0, 0, ISA_MIPS32R2, CPU_MIPS32R2 },
{ "m4kp", 0, 0, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "m14k", 0, ASE_MCU, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "m14kc", 0, ASE_MCU, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "m14ke", 0, ASE_DSP | ASE_DSPR2 | ASE_MCU,
+ { "m14k", 0, AFL_ASE_MCU, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "m14kc", 0, AFL_ASE_MCU, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "m14ke", 0, AFL_ASE_DSP | AFL_ASE_DSPR2 | AFL_ASE_MCU,
ISA_MIPS32R2, CPU_MIPS32R2 },
- { "m14kec", 0, ASE_DSP | ASE_DSPR2 | ASE_MCU,
+ { "m14kec", 0, AFL_ASE_DSP | AFL_ASE_DSPR2 | AFL_ASE_MCU,
ISA_MIPS32R2, CPU_MIPS32R2 },
{ "24kc", 0, 0, ISA_MIPS32R2, CPU_MIPS32R2 },
{ "24kf2_1", 0, 0, ISA_MIPS32R2, CPU_MIPS32R2 },
@@ -17879,50 +18147,70 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
{ "24kfx", 0, 0, ISA_MIPS32R2, CPU_MIPS32R2 },
{ "24kx", 0, 0, ISA_MIPS32R2, CPU_MIPS32R2 },
/* 24KE is a 24K with DSP ASE, other ASEs are optional. */
- { "24kec", 0, ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "24kef2_1", 0, ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "24kef", 0, ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "24kef1_1", 0, ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24kec", 0, AFL_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24kef2_1", 0, AFL_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24kef", 0, AFL_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24kef1_1", 0, AFL_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
/* Deprecated forms of the above. */
- { "24kefx", 0, ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "24kex", 0, ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24kefx", 0, AFL_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24kex", 0, AFL_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
/* 34K is a 24K with DSP and MT ASE, other ASEs are optional. */
- { "34kc", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "34kf2_1", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "34kf", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "34kf1_1", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "34kc", 0, AFL_ASE_DSP | AFL_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "34kf2_1", 0, AFL_ASE_DSP | AFL_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "34kf", 0, AFL_ASE_DSP | AFL_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "34kf1_1", 0, AFL_ASE_DSP | AFL_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
/* Deprecated forms of the above. */
- { "34kfx", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "34kx", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "34kfx", 0, AFL_ASE_DSP | AFL_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "34kx", 0, AFL_ASE_DSP | AFL_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
/* 34Kn is a 34kc without DSP. */
- { "34kn", 0, ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "34kn", 0, AFL_ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
/* 74K with DSP and DSPR2 ASE, other ASEs are optional. */
- { "74kc", 0, ASE_DSP | ASE_DSPR2, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "74kf2_1", 0, ASE_DSP | ASE_DSPR2, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "74kf", 0, ASE_DSP | ASE_DSPR2, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "74kf1_1", 0, ASE_DSP | ASE_DSPR2, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "74kf3_2", 0, ASE_DSP | ASE_DSPR2, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "74kc", 0, AFL_ASE_DSP | AFL_ASE_DSPR2,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "74kf2_1", 0, AFL_ASE_DSP | AFL_ASE_DSPR2,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "74kf", 0, AFL_ASE_DSP | AFL_ASE_DSPR2,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "74kf1_1", 0, AFL_ASE_DSP | AFL_ASE_DSPR2,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "74kf3_2", 0, AFL_ASE_DSP | AFL_ASE_DSPR2,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
/* Deprecated forms of the above. */
- { "74kfx", 0, ASE_DSP | ASE_DSPR2, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "74kx", 0, ASE_DSP | ASE_DSPR2, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "74kfx", 0, AFL_ASE_DSP | AFL_ASE_DSPR2,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "74kx", 0, AFL_ASE_DSP | AFL_ASE_DSPR2,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
/* 1004K cores are multiprocessor versions of the 34K. */
- { "1004kc", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "1004kf2_1", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "1004kf", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "1004kf1_1", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "1004kc", 0, AFL_ASE_DSP | AFL_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "1004kf2_1", 0, AFL_ASE_DSP | AFL_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "1004kf", 0, AFL_ASE_DSP | AFL_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "1004kf1_1", 0, AFL_ASE_DSP | AFL_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
/* P5600 with EVA and Virtualization ASEs, other ASEs are optional. */
- { "p5600", 0, ASE_VIRT | ASE_EVA | ASE_XPA, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "p5600", 0, AFL_ASE_VIRT | AFL_ASE_EVA | AFL_ASE_XPA,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
/* MIPS 64 */
{ "5kc", 0, 0, ISA_MIPS64, CPU_MIPS64 },
{ "5kf", 0, 0, ISA_MIPS64, CPU_MIPS64 },
- { "20kc", 0, ASE_MIPS3D, ISA_MIPS64, CPU_MIPS64 },
- { "25kf", 0, ASE_MIPS3D, ISA_MIPS64, CPU_MIPS64 },
+ { "20kc", 0, AFL_ASE_MIPS3D, ISA_MIPS64, CPU_MIPS64 },
+ { "25kf", 0, AFL_ASE_MIPS3D, ISA_MIPS64, CPU_MIPS64 },
/* Broadcom SB-1 CPU core */
- { "sb1", 0, ASE_MIPS3D | ASE_MDMX, ISA_MIPS64, CPU_SB1 },
+ { "sb1", 0, AFL_ASE_MIPS3D | AFL_ASE_MDMX,
+ ISA_MIPS64, CPU_SB1 },
/* Broadcom SB-1A CPU core */
- { "sb1a", 0, ASE_MIPS3D | ASE_MDMX, ISA_MIPS64, CPU_SB1 },
+ { "sb1a", 0, AFL_ASE_MIPS3D | AFL_ASE_MDMX,
+ ISA_MIPS64, CPU_SB1 },
{ "loongson3a", 0, 0, ISA_MIPS64R2, CPU_LOONGSON_3A },
@@ -18025,8 +18313,8 @@ mips_parse_cpu (const char *option, const char *cpu_string)
if (ABI_NEEDS_64BIT_REGS (mips_abi))
return mips_cpu_info_from_isa (ISA_MIPS3);
- if (file_mips_gp32 >= 0)
- return mips_cpu_info_from_isa (file_mips_gp32 ? ISA_MIPS1 : ISA_MIPS3);
+ if (file_mips_opts.gp32 >= 0)
+ return mips_cpu_info_from_isa (file_mips_opts.gp32 ? ISA_MIPS1 : ISA_MIPS3);
return mips_cpu_info_from_isa (MIPS_DEFAULT_64BIT
? ISA_MIPS3
@@ -18272,3 +18560,33 @@ tc_mips_regname_to_dw2regnum (char *regname)
return regnum;
}
+
+/* Given a symbolic attribute NAME, return the proper integer value.
+ Returns -1 if the attribute is not known. */
+
+int
+mips_convert_symbolic_attribute (const char *name)
+{
+ static const struct
+ {
+ const char * name;
+ const int tag;
+ }
+ attribute_table[] =
+ {
+#define T(tag) {#tag, tag}
+ T (Tag_GNU_MIPS_ABI_FP),
+ T (Tag_GNU_MIPS_ABI_MSA),
+#undef T
+ };
+ unsigned int i;
+
+ if (name == NULL)
+ return -1;
+
+ for (i = 0; i < ARRAY_SIZE (attribute_table); i++)
+ if (streq (name, attribute_table[i].name))
+ return attribute_table[i].tag;
+
+ return -1;
+}
diff --git a/gas/config/tc-mips.h b/gas/config/tc-mips.h
index 510e811..0a07f3a 100644
--- a/gas/config/tc-mips.h
+++ b/gas/config/tc-mips.h
@@ -194,4 +194,9 @@ extern int tc_mips_regname_to_dw2regnum (char *regname);
64-bit form for n64 CFIs. */
#define CFI_DIFF_EXPR_OK 0
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+#define CONVERT_SYMBOLIC_ATTRIBUTE(name) mips_convert_symbolic_attribute (name)
+extern int mips_convert_symbolic_attribute (const char *);
+#endif
+
#endif /* TC_MIPS */
diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo
index d16bbf6..e028823 100644
--- a/gas/doc/as.texinfo
+++ b/gas/doc/as.texinfo
@@ -399,6 +399,7 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}.
[@b{-g}[@var{debug level}]] [@b{-G} @var{num}] [@b{-KPIC}] [@b{-call_shared}]
[@b{-non_shared}] [@b{-xgot} [@b{-mvxworks-pic}]
[@b{-mabi}=@var{ABI}] [@b{-32}] [@b{-n32}] [@b{-64}] [@b{-mfp32}] [@b{-mgp32}]
+ [@b{-mfp64}] [@b{-mgp64}] [@b{-mfpxx}]
[@b{-march}=@var{CPU}] [@b{-mtune}=@var{CPU}] [@b{-mips1}] [@b{-mips2}]
[@b{-mips3}] [@b{-mips4}] [@b{-mips5}] [@b{-mips32}] [@b{-mips32r2}]
[@b{-mips64}] [@b{-mips64r2}]
@@ -1308,6 +1309,19 @@ flags force a certain group of registers to be treated as 32 bits wide at
all times. @samp{-mgp32} controls the size of general-purpose registers
and @samp{-mfp32} controls the size of floating-point registers.
+@item -mgp64
+@itemx -mfp64
+The register sizes are normally inferred from the ISA and ABI, but these
+flags force a certain group of registers to be treated as 64 bits wide at
+all times. @samp{-mgp64} controls the size of general-purpose registers
+and @samp{-mfp64} controls the size of floating-point registers.
+
+@item -mfpxx
+The register sizes are normally inferred from the ISA and ABI, but using
+this flag in combination with @samp{-mabi=32} enables an ABI variant
+which will operate correctly with floating-point registers which are
+32 or 64 bits wide.
+
@item -mips16
@itemx -no-mips16
Generate code for the MIPS 16 processor. This is equivalent to putting
diff --git a/gas/doc/c-mips.texi b/gas/doc/c-mips.texi
index 0c5e82d..37926d4 100644
--- a/gas/doc/c-mips.texi
+++ b/gas/doc/c-mips.texi
@@ -28,6 +28,7 @@ Assembly Language Programming'' in the same work.
* MIPS assembly options:: Directives to control code generation
* MIPS autoextend:: Directives for extending MIPS 16 bit instructions
* MIPS insn:: Directive to mark data as an instruction
+* MIPS FP ABIs:: Marking which FP ABI is in use
* MIPS NaN Encodings:: Directives to record which NaN encoding is being used
* MIPS Option Stack:: Directives to save and restore options
* MIPS ASE Instruction Generation Overrides:: Directives to control
@@ -119,6 +120,15 @@ The @code{.set gp=64} and @code{.set fp=64} directives allow the size
of registers to be changed for parts of an object. The default value is
restored by @code{.set gp=default} and @code{.set fp=default}.
+@item -mfpxx
+Make no assumptions about whether 32-bit or 64-bit registers are available.
+This is provided to support having modules compatible with either
+@samp{-mfp32} or @samp{-mfp64}. This option can only be used with MIPS II
+and above.
+
+The @code{.set fp=xx} directive allows a part of an object to be marked
+as not making assumptions about 32-bit or 64-bita FP registers. The
+default value is restored by @code{.set fp=default}.
@item -mips16
@itemx -no-mips16
Generate code for the MIPS 16 processor. This is equivalent to putting
@@ -687,6 +697,22 @@ Traditional MIPS assemblers do not support this directive.
@node MIPS assembly options
@section Directives to control code generation
+@cindex MIPS directives to override command line options
+@kindex @code{.module}
+The @code{.module} directive allows command line options to be set directly
+from assembly. The format of the directive matches the @code{.set}
+directive but only those options which are relevant to a whole module are
+supported. The effect of a @code{.module} directive is the same as the
+corresponding command line option. Where @code{.set} directives support
+returning to a default then the @code{.module} directives do not as they
+define the defaults.
+
+These module level directives must appear first in assembly and will raise
+a warning if found after the first instruction, @code{.set} directive or
+any code generating directive.
+
+Traditional MIPS assemblers do not support this directive.
+
@cindex MIPS 32-bit microMIPS instruction generation override
@kindex @code{.set insn32}
@kindex @code{.set noinsn32}
@@ -749,6 +775,108 @@ baz:
@end example
+@node MIPS FP ABIs
+@section Directives to control the FP ABI
+@menu
+* MIPS FP ABI History:: History of FP ABIs
+* MIPS FP ABI Variants:: Supported FP ABIs
+* MIPS FP ABI Selection:: Automatic selection of FP ABI
+* MIPS FP ABI Compatibility:: Linking different FP ABI variants
+@end menu
+
+@node MIPS FP ABI History
+@subsection History of FP ABIs
+@cindex @code{.gnu_attribute 4, @var{n}} directive, MIPS
+@cindex @code{.gnu_attribute Tag_GNU_MIPS_ABI_FP, @var{n}} directive, MIPS
+The MIPS ABIs support a variety of different floating-point extensions
+where calling-convention and register sizes vary for floating-point data.
+The extensions exist to support a wide variety of optional architecture
+features. The resulting ABI variants are generally incompatible with each
+other and must be tracked carefully.
+
+Traditionally the use of an explicit @code{.gnu_attribute 4, @var{n}}
+directive is used to indicate which ABI is in use by a specific module.
+It was then left to the user to ensure that command line options and the
+selected ABI were compatible with some potential for inconsistencies.
+
+@node MIPS FP ABI Variants
+@subsection Supported FP ABIs
+The supported floating-point ABI variants are:
+
+@table @code
+@item 0 - No floating-point
+This variant is used to indicate that floating-point is not used within
+the module at all and therefore has no impact on the ABI. This is the
+default.
+
+@item 1 - Double-precision
+This variant indicates that double-precision support is used. For 64-bit
+ABIs this means that 64-bit wide floating-point registers are required.
+For 32-bit ABIs this means that 32-bit wide floating-point registers are
+required and double precision operations across pairs of registers.
+
+@item 2 - Single-precision
+This variant indicates that single-precision support is used. This is
+generally taken to mean that the ABI is also modified such that
+sizeof (double) == sizeof (float). This has an impact on calling
+convention and callee-save behaviour.
+
+@item 3 - Soft-float
+This variant indicates that although floating-point support is used all
+operations are emulated in software. This means the ABI is modified to
+pass all floating-point data in general-purpose registers.
+
+@item 4 - Deprecated
+This variant existed as an initial attempt at supporting 64-bit wide
+floating-point registers for O32 ABI on a MIPS32r2 cpu. This has been
+superceded by @value{5} and @value{6}.
+
+@item 5 - Double-precision 32-bit CPU, 32-bit or 64-bit FPU
+This variant is used by 32-bit ABIs to indicate that the floating-point
+code in the module has been designed to operate correctly with either
+32-bit wide or 64-bit wide floating-point registers. Double precision
+support is used. Only O32 currently supports this variant and requires
+a minimum architecture of MIPS II.
+
+@item 6 - Double-precision 32-bit FPU, 64-bit FPU
+This variant is used by 32-bit ABIs to indicate that the floating-point
+code in the module requires 64-bit wide floating-point registers.
+Double precision support is used. Only O32 currently supports this
+variant and requires a minimum architecture of MIPS32r2.
+@end table
+
+@node MIPS FP ABI Selection
+@subsection Automatic selection of FP ABI
+@cindex @code{.module fp=@var{nn}} directive, MIPS
+In order to simplify and add safety to the process of selecting the
+correct floating-point ABI, the assembler will automatically infer the
+correct @code{.gnu_attribute 4, @var{n}} directive based on command line
+options @code{.module} overrides and instruction usage. Where an explicit
+@code{.gnu_attribute 4, @var{n}} directive has been seen then a warning
+will be raised if it does not match an inferred setting.
+
+The floating-point ABI is inferred as follows. If @samp{-msoft-float}
+has been used the module will be marked as soft-float. The hard-float
+ABIs are then only inferred if a floating point instruction is seen.
+Firstly, if @samp{-msingle-float} has been used then the module will
+be marked as single-precision. The remaining ABIs are selected based
+on the FP register width. Double-precision is selected if the width
+of GP and FP registers match and the special double precision variants
+for 32-bit ABIs are then selected depending on @samp{-mfpxx} and
+@samp{-mfp64}.
+
+@node MIPS FP ABI Compatibility
+@subsection Linking different FP ABI variants
+Modules using the default FP ABI (no floating-point) can be linked with
+any other (singular) FP ABI variant.
+
+Special compatibility support exists for O32 with the three
+double-precision FP ABI variants. The @samp{-mfpxx} FP ABI is explicitly
+designed to be compatible with both the standard double-precision ABI and
+the @samp{-mfp64} FP ABI. This makes it desirable for O32 modules to be
+built as @samp{-mfpxx} to ensure the maximum compatibility with other
+modules produced for more specific needs.
+
@node MIPS NaN Encodings
@section Directives to record which NaN encoding is being used
diff --git a/include/elf/mips.h b/include/elf/mips.h
index 2949629..1fb3c70 100644
--- a/include/elf/mips.h
+++ b/include/elf/mips.h
@@ -428,6 +428,8 @@ END_RELOC_NUMBERS (R_MIPS_maxext)
/* Runtime procedure descriptor table exception information (ucode) ??? */
#define SHT_MIPS_PDR_EXCEPTION 0x70000029
+/* ABI related flags section. */
+#define SHT_MIPS_ABIFLAGS 0x7000002a
/* A section of type SHT_MIPS_LIBLIST contains an array of the
following structure. The sh_link field is the section index of the
@@ -593,6 +595,9 @@ extern void bfd_mips_elf32_swap_reginfo_out
/* .MIPS.options section. */
#define PT_MIPS_OPTIONS 0x70000002
+
+/* Records ABI related flags. */
+#define PT_MIPS_ABIFLAGS 0x70000003
/* Processor specific dynamic array tags. */
@@ -1048,6 +1053,58 @@ typedef struct
bfd_vma ri_gp_value;
} Elf64_Internal_RegInfo;
+/* ABI Flags structure version 0. */
+
+typedef struct
+{
+ /* Version of flags structure. */
+ unsigned char version[2];
+ /* The level of the ISA: 1-5, 32, 64. */
+ unsigned char isa_level[1];
+ /* The revision of ISA: 0 for MIPS V and below, 1-n otherwise. */
+ unsigned char isa_rev[1];
+ /* The size of general purpose registers. */
+ unsigned char gpr_size[1];
+ /* The size of co-processor 1 registers. */
+ unsigned char cpr1_size[1];
+ /* The size of co-processor 2 registers. */
+ unsigned char cpr2_size[1];
+ /* The floating-point ABI. */
+ unsigned char fp_abi[1];
+ /* Mask of processor-specific extensions. */
+ unsigned char isa_ext[4];
+ /* Mask of ASEs used. */
+ unsigned char ases[4];
+ /* Mask of general flags. */
+ unsigned char flags1[4];
+ unsigned char flags2[4];
+} Elf_External_ABIFlags_v0;
+
+typedef struct
+{
+ /* Version of flags structure. */
+ unsigned short version;
+ /* The level of the ISA: 1-5, 32, 64. */
+ unsigned char isa_level;
+ /* The revision of ISA: 0 for MIPS V and below, 1-n otherwise. */
+ unsigned char isa_rev;
+ /* The size of general purpose registers. */
+ unsigned char gpr_size;
+ /* The size of co-processor 1 registers. */
+ unsigned char cpr1_size;
+ /* The size of co-processor 2 registers. */
+ unsigned char cpr2_size;
+ /* The floating-point ABI. */
+ unsigned char fp_abi;
+ /* Mask of processor-specific extensions. */
+ unsigned long isa_ext;
+ /* Mask of ASEs used. */
+ unsigned long ases;
+ /* Mask of general flags. */
+ unsigned long flags1;
+ unsigned long flags2;
+} Elf_Internal_ABIFlags_v0;
+
typedef struct
{
/* The hash value computed from the name of the corresponding
@@ -1088,6 +1145,12 @@ extern void bfd_mips_elf64_swap_reginfo_in
extern void bfd_mips_elf64_swap_reginfo_out
(bfd *, const Elf64_Internal_RegInfo *, Elf64_External_RegInfo *);
+/* MIPS ELF flags swapping routines. */
+extern void bfd_mips_elf_swap_abiflags_v0_in
+ (bfd *, const Elf_External_ABIFlags_v0 *, Elf_Internal_ABIFlags_v0 *);
+extern void bfd_mips_elf_swap_abiflags_v0_out
+ (bfd *, const Elf_Internal_ABIFlags_v0 *, Elf_External_ABIFlags_v0 *);
+
/* Masks for the info work of an ODK_EXCEPTIONS descriptor. */
#define OEX_FPU_MIN 0x1f /* FPEs which must be enabled. */
#define OEX_FPU_MAX 0x1f00 /* FPEs which may be enabled. */
@@ -1125,6 +1188,53 @@ extern void bfd_mips_elf64_swap_reginfo_out
/* Masks for the info word of an ODK_HWAND/ODK_HWOR descriptor. */
#define OHWA0_R4KEOP_CHECKED 0x00000001
#define OHWA0_R4KEOP_CLEAN 0x00000002
+
+/* Values for the xxx_size bytes of an ABI flags structure. */
+
+#define AFL_REG_NONE 0x00 /* No registers. */
+#define AFL_REG_32 0x01 /* 32-bit registers. */
+#define AFL_REG_64 0x02 /* 64-bit registers. */
+#define AFL_REG_128 0x03 /* 128-bit registers. */
+
+/* Masks for the ases word of an ABI flags structure. */
+
+#define AFL_ASE_DSP 0x00000001 /* DSP ASE. */
+#define AFL_ASE_DSP64 0x00000002 /* DSP ASE (64-bit). */
+#define AFL_ASE_DSPR2 0x00000004 /* DSP R2 ASE. */
+#define AFL_ASE_EVA 0x00000008 /* Enhanced VA Scheme. */
+#define AFL_ASE_MCU 0x00000010 /* MCU (MicroController) ASE. */
+#define AFL_ASE_MDMX 0x00000020 /* MDMX ASE. */
+#define AFL_ASE_MIPS3D 0x00000040 /* MIPS-3D ASE. */
+#define AFL_ASE_MT 0x00000080 /* MT ASE. */
+#define AFL_ASE_SMARTMIPS 0x00000100 /* SmartMIPS ASE. */
+#define AFL_ASE_VIRT 0x00000200 /* VZ ASE. */
+#define AFL_ASE_VIRT64 0x00000400 /* VZ ASE (64-bit). */
+#define AFL_ASE_MSA 0x00000800 /* MSA ASE. */
+#define AFL_ASE_MSA64 0x00001000 /* MSA ASE (64-bit). */
+#define AFL_ASE_MIPS16 0x00002000 /* MIPS16 ASE. */
+#define AFL_ASE_MICROMIPS 0x00004000 /* MICROMIPS ASE. */
+#define AFL_ASE_XPA 0x00002000 /* XPA ASE. */
+
+/* Masks for the isa_ext word of an ABI flags structure. */
+
+#define AFL_EXT_XLR 0x00000020 /* RMI Xlr instruction. */
+#define AFL_EXT_OCTEON2 0x00000100 /* Cavium Networks Octeon2. */
+#define AFL_EXT_OCTEONP 0x00000200 /* Cavium Networks OcteonP. */
+#define AFL_EXT_LOONGSON_3A 0x00000400 /* Loongson 3A. */
+#define AFL_EXT_OCTEON 0x00000800 /* Cavium Networks Octeon. */
+#define AFL_EXT_5900 0x00004000 /* MIPS R5900 instruction. */
+#define AFL_EXT_4650 0x00010000 /* MIPS R4650 instruction. */
+#define AFL_EXT_4010 0x00020000 /* LSI R4010 instruction. */
+#define AFL_EXT_4100 0x00040000 /* NEC VR4100 instruction. */
+#define AFL_EXT_3900 0x00080000 /* Toshiba R3900 instruction. */
+#define AFL_EXT_10000 0x00100000 /* MIPS R10000 instruction. */
+#define AFL_EXT_SB1 0x00200000 /* Broadcom SB-1 instruction. */
+#define AFL_EXT_4111 0x00400000 /* NEC VR4111/VR4181 instruction. */
+#define AFL_EXT_4120 0x00800000 /* NEC VR4120 instruction. */
+#define AFL_EXT_5400 0x01000000 /* NEC VR5400 instruction. */
+#define AFL_EXT_5500 0x02000000 /* NEC VR5500 instruction. */
+#define AFL_EXT_LOONGSON_2E 0x40000000 /* ST Microelectronics Loongson 2E. */
+#define AFL_EXT_LOONGSON_2F 0x80000000 /* ST Microelectronics Loongson 2F. */
/* Object attribute tags. */
@@ -1157,7 +1267,13 @@ enum
Val_GNU_MIPS_ABI_FP_SOFT = 3,
/* Using -mips32r2 -mfp64. */
- Val_GNU_MIPS_ABI_FP_64 = 4,
+ Val_GNU_MIPS_ABI_FP_OLD_64 = 4,
+
+ /* Using -mfpxx */
+ Val_GNU_MIPS_ABI_FP_XX = 5,
+
+ /* Using -mips32r2 -mfp64. */
+ Val_GNU_MIPS_ABI_FP_64 = 6,
/* Values defined for Tag_GNU_MIPS_ABI_MSA. */
diff --git a/include/opcode/mips.h b/include/opcode/mips.h
index 364f267..52ec6bc 100644
--- a/include/opcode/mips.h
+++ b/include/opcode/mips.h
@@ -24,6 +24,7 @@
#define _MIPS_H_
#include "bfd.h"
+#include "elf/mips.h"
/* These are bit masks and shift counts to use to access the various
fields of an instruction. To retrieve the X field of an
@@ -1108,73 +1109,6 @@ static const unsigned int mips_isa_table[] = {
};
#undef ISAF
-/* Masks used for Chip specific instructions. */
-#define INSN_CHIP_MASK 0xc3ff0f20
-
-/* Cavium Networks Octeon instructions. */
-#define INSN_OCTEON 0x00000800
-#define INSN_OCTEONP 0x00000200
-#define INSN_OCTEON2 0x00000100
-
-/* MIPS R5900 instruction */
-#define INSN_5900 0x00004000
-
-/* MIPS R4650 instruction. */
-#define INSN_4650 0x00010000
-/* LSI R4010 instruction. */
-#define INSN_4010 0x00020000
-/* NEC VR4100 instruction. */
-#define INSN_4100 0x00040000
-/* Toshiba R3900 instruction. */
-#define INSN_3900 0x00080000
-/* MIPS R10000 instruction. */
-#define INSN_10000 0x00100000
-/* Broadcom SB-1 instruction. */
-#define INSN_SB1 0x00200000
-/* NEC VR4111/VR4181 instruction. */
-#define INSN_4111 0x00400000
-/* NEC VR4120 instruction. */
-#define INSN_4120 0x00800000
-/* NEC VR5400 instruction. */
-#define INSN_5400 0x01000000
-/* NEC VR5500 instruction. */
-#define INSN_5500 0x02000000
-
-/* ST Microelectronics Loongson 2E. */
-#define INSN_LOONGSON_2E 0x40000000
-/* ST Microelectronics Loongson 2F. */
-#define INSN_LOONGSON_2F 0x80000000
-/* Loongson 3A. */
-#define INSN_LOONGSON_3A 0x00000400
-/* RMI Xlr instruction */
-#define INSN_XLR 0x00000020
-
-/* DSP ASE */
-#define ASE_DSP 0x00000001
-#define ASE_DSP64 0x00000002
-/* DSP R2 ASE */
-#define ASE_DSPR2 0x00000004
-/* Enhanced VA Scheme */
-#define ASE_EVA 0x00000008
-/* MCU (MicroController) ASE */
-#define ASE_MCU 0x00000010
-/* MDMX ASE */
-#define ASE_MDMX 0x00000020
-/* MIPS-3D ASE */
-#define ASE_MIPS3D 0x00000040
-/* MT ASE */
-#define ASE_MT 0x00000080
-/* SmartMIPS ASE */
-#define ASE_SMARTMIPS 0x00000100
-/* Virtualization ASE */
-#define ASE_VIRT 0x00000200
-#define ASE_VIRT64 0x00000400
-/* MSA Extension */
-#define ASE_MSA 0x00000800
-#define ASE_MSA64 0x00001000
-/* eXtended Physical Address (XPA) Extension. */
-#define ASE_XPA 0x00002000
-
/* MIPS ISA defines, use instead of hardcoding ISA level. */
#define ISA_UNKNOWN 0 /* Gas internal use. */
@@ -1234,75 +1168,81 @@ static const unsigned int mips_isa_table[] = {
/* Return true if the given CPU is included in INSN_* mask MASK. */
-static inline bfd_boolean
-cpu_is_member (int cpu, unsigned int mask)
+static inline unsigned long
+cpu_insn_mask (int cpu)
{
switch (cpu)
{
case CPU_R4650:
case CPU_RM7000:
case CPU_RM9000:
- return (mask & INSN_4650) != 0;
+ return AFL_EXT_4650;
case CPU_R4010:
- return (mask & INSN_4010) != 0;
+ return AFL_EXT_4010;
case CPU_VR4100:
- return (mask & INSN_4100) != 0;
+ return AFL_EXT_4100;
case CPU_R3900:
- return (mask & INSN_3900) != 0;
+ return AFL_EXT_3900;
case CPU_R10000:
case CPU_R12000:
case CPU_R14000:
case CPU_R16000:
- return (mask & INSN_10000) != 0;
+ return AFL_EXT_10000;
case CPU_SB1:
- return (mask & INSN_SB1) != 0;
+ return AFL_EXT_SB1;
case CPU_R4111:
- return (mask & INSN_4111) != 0;
+ return AFL_EXT_4111;
case CPU_VR4120:
- return (mask & INSN_4120) != 0;
+ return AFL_EXT_4120;
case CPU_VR5400:
- return (mask & INSN_5400) != 0;
+ return AFL_EXT_5400;
case CPU_VR5500:
- return (mask & INSN_5500) != 0;
+ return AFL_EXT_5500;
case CPU_R5900:
- return (mask & INSN_5900) != 0;
+ return AFL_EXT_5900;
case CPU_LOONGSON_2E:
- return (mask & INSN_LOONGSON_2E) != 0;
+ return AFL_EXT_LOONGSON_2E;
case CPU_LOONGSON_2F:
- return (mask & INSN_LOONGSON_2F) != 0;
+ return AFL_EXT_LOONGSON_2F;
case CPU_LOONGSON_3A:
- return (mask & INSN_LOONGSON_3A) != 0;
+ return AFL_EXT_LOONGSON_3A;
case CPU_OCTEON:
- return (mask & INSN_OCTEON) != 0;
+ return AFL_EXT_OCTEON;
case CPU_OCTEONP:
- return (mask & INSN_OCTEONP) != 0;
+ return AFL_EXT_OCTEONP;
case CPU_OCTEON2:
- return (mask & INSN_OCTEON2) != 0;
+ return AFL_EXT_OCTEON2;
case CPU_XLR:
- return (mask & INSN_XLR) != 0;
+ return AFL_EXT_XLR;
default:
- return FALSE;
+ return 0;
}
}
+static inline bfd_boolean
+cpu_is_member (int cpu, unsigned int mask)
+{
+ return (cpu_insn_mask (cpu) & mask) != 0;
+}
+
/* Test for membership in an ISA including chip specific ISAs. INSN
is pointer to an element of the opcode table; ISA is the specified
ISA/ASE bitmask to test against; and CPU is the CPU specific ISA to
diff --git a/ld/emulparams/elf32bmip.sh b/ld/emulparams/elf32bmip.sh
index 118d57a..8da0f8f 100644
--- a/ld/emulparams/elf32bmip.sh
+++ b/ld/emulparams/elf32bmip.sh
@@ -17,7 +17,8 @@ if test -z "${CREATE_SHLIB}"; then
INITIAL_READONLY_SECTIONS=".interp ${RELOCATING-0} : { *(.interp) }"
fi
INITIAL_READONLY_SECTIONS="${INITIAL_READONLY_SECTIONS}
- .reginfo ${RELOCATING-0} : { *(.reginfo) }
+ .MIPS.abiflags ${RELOCATING-0} : { *(.MIPS.abiflags) }
+ .reginfo ${RELOCATING-0} : { *(.reginfo) }
"
OTHER_TEXT_SECTIONS='*(.mips16.fn.*) *(.mips16.call.*)'
# Unlike most targets, the MIPS backend puts all dynamic relocations
diff --git a/ld/emulparams/elf32bmipn32-defs.sh b/ld/emulparams/elf32bmipn32-defs.sh
index 514990b..723eac8 100644
--- a/ld/emulparams/elf32bmipn32-defs.sh
+++ b/ld/emulparams/elf32bmipn32-defs.sh
@@ -88,6 +88,7 @@ if test -z "${CREATE_SHLIB}"; then
INITIAL_READONLY_SECTIONS=".interp ${RELOCATING-0} : { *(.interp) }"
fi
INITIAL_READONLY_SECTIONS="${INITIAL_READONLY_SECTIONS}
+ .MIPS.abiflags ${RELOCATING-0} : { *(.MIPS.abiflags) }
.reginfo ${RELOCATING-0} : { *(.reginfo) }"
# Discard any .MIPS.content* or .MIPS.events* sections. The linker
# doesn't know how to adjust them.
diff --git a/opcodes/micromips-opc.c b/opcodes/micromips-opc.c
index af7cbf6..c688065 100644
--- a/opcodes/micromips-opc.c
+++ b/opcodes/micromips-opc.c
@@ -257,25 +257,25 @@ decode_micromips_operand (const char *p)
#define RD_a RD_HILO /* Read DSP accumulators (reuse RD_HILO). */
#define MOD_a WR_a|RD_a
#define DSP_VOLA INSN_NO_DELAY_SLOT
-#define D32 ASE_DSP
-#define D33 ASE_DSPR2
+#define D32 AFL_ASE_DSP
+#define D33 AFL_ASE_DSPR2
/* MIPS MCU (MicroController) ASE support. */
-#define MC ASE_MCU
+#define MC AFL_ASE_MCU
/* MIPS Enhanced VA Scheme. */
-#define EVA ASE_EVA
+#define EVA AFL_ASE_EVA
/* TLB invalidate instruction support. */
-#define TLBINV ASE_EVA
+#define TLBINV AFL_ASE_EVA
/* MIPS Virtualization ASE. */
-#define IVIRT ASE_VIRT
-#define IVIRT64 ASE_VIRT64
+#define IVIRT AFL_ASE_VIRT
+#define IVIRT64 AFL_ASE_VIRT64
/* MSA support. */
-#define MSA ASE_MSA
-#define MSA64 ASE_MSA64
+#define MSA AFL_ASE_MSA
+#define MSA64 AFL_ASE_MSA64
const struct mips_opcode micromips_opcodes[] =
{
diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c
index 0f8624e..658916e 100644
--- a/opcodes/mips-dis.c
+++ b/opcodes/mips-dis.c
@@ -543,66 +543,68 @@ const struct mips_arch_choice mips_arch_choices[] =
MIPS32 Architecture_ (MIPS Document Number MD00082, Revision 0.95),
page 1. */
{ "mips32", 1, bfd_mach_mipsisa32, CPU_MIPS32,
- ISA_MIPS32, ASE_SMARTMIPS,
+ ISA_MIPS32, AFL_ASE_SMARTMIPS,
mips_cp0_names_mips3264,
mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
mips_cp1_names_mips3264, mips_hwr_names_numeric },
{ "mips32r2", 1, bfd_mach_mipsisa32r2, CPU_MIPS32R2,
ISA_MIPS32R2,
- (ASE_SMARTMIPS | ASE_DSP | ASE_DSPR2 | ASE_EVA | ASE_MIPS3D
- | ASE_MT | ASE_MCU | ASE_VIRT | ASE_MSA | ASE_XPA),
+ (AFL_ASE_SMARTMIPS | AFL_ASE_DSP | AFL_ASE_DSPR2 | AFL_ASE_EVA
+ | AFL_ASE_MIPS3D | AFL_ASE_MT | AFL_ASE_MCU | AFL_ASE_VIRT | AFL_ASE_MSA
+ | AFL_ASE_XPA),
mips_cp0_names_mips3264r2,
mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
/* For stock MIPS64, disassemble all applicable MIPS-specified ASEs. */
{ "mips64", 1, bfd_mach_mipsisa64, CPU_MIPS64,
- ISA_MIPS64, ASE_MIPS3D | ASE_MDMX,
+ ISA_MIPS64, AFL_ASE_MIPS3D | AFL_ASE_MDMX,
mips_cp0_names_mips3264,
mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
mips_cp1_names_mips3264, mips_hwr_names_numeric },
{ "mips64r2", 1, bfd_mach_mipsisa64r2, CPU_MIPS64R2,
ISA_MIPS64R2,
- (ASE_MIPS3D | ASE_DSP | ASE_DSPR2 | ASE_DSP64 | ASE_EVA | ASE_MT
- | ASE_MCU | ASE_VIRT | ASE_VIRT64 | ASE_MSA | ASE_MSA64 | ASE_XPA),
+ (AFL_ASE_MIPS3D | AFL_ASE_DSP | AFL_ASE_DSPR2 | AFL_ASE_DSP64 | AFL_ASE_EVA
+ | AFL_ASE_MT | AFL_ASE_MCU | AFL_ASE_VIRT | AFL_ASE_VIRT64 | AFL_ASE_MSA
+ | AFL_ASE_MSA64 | AFL_ASE_XPA),
mips_cp0_names_mips3264r2,
mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
{ "sb1", 1, bfd_mach_mips_sb1, CPU_SB1,
- ISA_MIPS64 | INSN_SB1, ASE_MIPS3D,
+ ISA_MIPS64 | AFL_EXT_SB1, AFL_ASE_MIPS3D,
mips_cp0_names_sb1,
mips_cp0sel_names_sb1, ARRAY_SIZE (mips_cp0sel_names_sb1),
mips_cp1_names_mips3264, mips_hwr_names_numeric },
{ "loongson2e", 1, bfd_mach_mips_loongson_2e, CPU_LOONGSON_2E,
- ISA_MIPS3 | INSN_LOONGSON_2E, 0, mips_cp0_names_numeric,
+ ISA_MIPS3 | AFL_EXT_LOONGSON_2E, 0, mips_cp0_names_numeric,
NULL, 0, mips_cp1_names_numeric, mips_hwr_names_numeric },
{ "loongson2f", 1, bfd_mach_mips_loongson_2f, CPU_LOONGSON_2F,
- ISA_MIPS3 | INSN_LOONGSON_2F, 0, mips_cp0_names_numeric,
+ ISA_MIPS3 | AFL_EXT_LOONGSON_2F, 0, mips_cp0_names_numeric,
NULL, 0, mips_cp1_names_numeric, mips_hwr_names_numeric },
{ "loongson3a", 1, bfd_mach_mips_loongson_3a, CPU_LOONGSON_3A,
- ISA_MIPS64R2 | INSN_LOONGSON_3A, 0, mips_cp0_names_numeric,
+ ISA_MIPS64R2 | AFL_EXT_LOONGSON_3A, 0, mips_cp0_names_numeric,
NULL, 0, mips_cp1_names_mips3264, mips_hwr_names_numeric },
{ "octeon", 1, bfd_mach_mips_octeon, CPU_OCTEON,
- ISA_MIPS64R2 | INSN_OCTEON, 0, mips_cp0_names_numeric, NULL, 0,
+ ISA_MIPS64R2 | AFL_EXT_OCTEON, 0, mips_cp0_names_numeric, NULL, 0,
mips_cp1_names_mips3264, mips_hwr_names_numeric },
{ "octeon+", 1, bfd_mach_mips_octeonp, CPU_OCTEONP,
- ISA_MIPS64R2 | INSN_OCTEONP, 0, mips_cp0_names_numeric,
+ ISA_MIPS64R2 | AFL_EXT_OCTEONP, 0, mips_cp0_names_numeric,
NULL, 0, mips_cp1_names_mips3264, mips_hwr_names_numeric },
{ "octeon2", 1, bfd_mach_mips_octeon2, CPU_OCTEON2,
- ISA_MIPS64R2 | INSN_OCTEON2, 0, mips_cp0_names_numeric,
+ ISA_MIPS64R2 | AFL_EXT_OCTEON2, 0, mips_cp0_names_numeric,
NULL, 0, mips_cp1_names_mips3264, mips_hwr_names_numeric },
{ "xlr", 1, bfd_mach_mips_xlr, CPU_XLR,
- ISA_MIPS64 | INSN_XLR, 0,
+ ISA_MIPS64 | AFL_EXT_XLR, 0,
mips_cp0_names_xlr,
mips_cp0sel_names_xlr, ARRAY_SIZE (mips_cp0sel_names_xlr),
mips_cp1_names_mips3264, mips_hwr_names_numeric },
@@ -610,7 +612,7 @@ const struct mips_arch_choice mips_arch_choices[] =
/* XLP is mostly like XLR, with the prominent exception it is being
MIPS64R2. */
{ "xlp", 1, bfd_mach_mips_xlr, CPU_XLR,
- ISA_MIPS64R2 | INSN_XLR, 0,
+ ISA_MIPS64R2 | AFL_EXT_XLR, 0,
mips_cp0_names_xlr,
mips_cp0sel_names_xlr, ARRAY_SIZE (mips_cp0sel_names_xlr),
mips_cp1_names_mips3264, mips_hwr_names_numeric },
@@ -797,23 +799,23 @@ parse_mips_dis_option (const char *option, unsigned int len)
if (CONST_STRNEQ (option, "msa"))
{
- mips_ase |= ASE_MSA;
+ mips_ase |= AFL_ASE_MSA;
if ((mips_isa & INSN_ISA_MASK) == ISA_MIPS64R2)
- mips_ase |= ASE_MSA64;
+ mips_ase |= AFL_ASE_MSA64;
return;
}
if (CONST_STRNEQ (option, "virt"))
{
- mips_ase |= ASE_VIRT;
+ mips_ase |= AFL_ASE_VIRT;
if (mips_isa & ISA_MIPS64R2)
- mips_ase |= ASE_VIRT64;
+ mips_ase |= AFL_ASE_VIRT64;
return;
}
if (CONST_STRNEQ (option, "xpa"))
{
- mips_ase |= ASE_XPA;
+ mips_ase |= AFL_ASE_XPA;
return;
}
@@ -979,7 +981,7 @@ print_reg (struct disassemble_info *info, const struct mips_opcode *opcode,
break;
case OP_REG_VEC:
- if (opcode->membership & INSN_5400)
+ if (opcode->membership & AFL_EXT_5400)
info->fprintf_func (info->stream, "$f%d", regno);
else
info->fprintf_func (info->stream, "$v%d", regno);
diff --git a/opcodes/mips-opc.c b/opcodes/mips-opc.c
index 9181c3f..bb7d035 100644
--- a/opcodes/mips-opc.c
+++ b/opcodes/mips-opc.c
@@ -257,37 +257,37 @@ decode_mips_operand (const char *p)
#define I5_33 INSN_ISA5_32R2
/* MIPS64 MIPS-3D ASE support. */
-#define M3D ASE_MIPS3D
+#define M3D AFL_ASE_MIPS3D
/* MIPS32 SmartMIPS ASE support. */
-#define SMT ASE_SMARTMIPS
+#define SMT AFL_ASE_SMARTMIPS
/* MIPS64 MDMX ASE support. */
-#define MX ASE_MDMX
+#define MX AFL_ASE_MDMX
-#define IL2E (INSN_LOONGSON_2E)
-#define IL2F (INSN_LOONGSON_2F)
-#define IL3A (INSN_LOONGSON_3A)
+#define IL2E (AFL_EXT_LOONGSON_2E)
+#define IL2F (AFL_EXT_LOONGSON_2F)
+#define IL3A (AFL_EXT_LOONGSON_3A)
-#define P3 INSN_4650
-#define L1 INSN_4010
-#define V1 (INSN_4100 | INSN_4111 | INSN_4120)
-#define T3 INSN_3900
+#define P3 AFL_EXT_4650
+#define L1 AFL_EXT_4010
+#define V1 (AFL_EXT_4100 | AFL_EXT_4111 | AFL_EXT_4120)
+#define T3 AFL_EXT_3900
/* Emotion Engine MIPS r5900. */
-#define EE INSN_5900
-#define M1 INSN_10000
-#define SB1 INSN_SB1
-#define N411 INSN_4111
-#define N412 INSN_4120
-#define N5 (INSN_5400 | INSN_5500)
-#define N54 INSN_5400
-#define N55 INSN_5500
-#define IOCT (INSN_OCTEON | INSN_OCTEONP | INSN_OCTEON2)
-#define IOCTP (INSN_OCTEONP | INSN_OCTEON2)
-#define IOCT2 INSN_OCTEON2
-#define XLR INSN_XLR
-#define IVIRT ASE_VIRT
-#define IVIRT64 ASE_VIRT64
+#define EE AFL_EXT_5900
+#define M1 AFL_EXT_10000
+#define SB1 AFL_EXT_SB1
+#define N411 AFL_EXT_4111
+#define N412 AFL_EXT_4120
+#define N5 (AFL_EXT_5400 | AFL_EXT_5500)
+#define N54 AFL_EXT_5400
+#define N55 AFL_EXT_5500
+#define IOCT (AFL_EXT_OCTEON | AFL_EXT_OCTEONP | AFL_EXT_OCTEON2)
+#define IOCTP (AFL_EXT_OCTEONP | AFL_EXT_OCTEON2)
+#define IOCT2 AFL_EXT_OCTEON2
+#define XLR AFL_EXT_XLR
+#define IVIRT AFL_ASE_VIRT
+#define IVIRT64 AFL_ASE_VIRT64
#define G1 (T3 \
|EE \
@@ -339,28 +339,28 @@ decode_mips_operand (const char *p)
#define RD_a RD_HILO /* Read dsp accumulators (reuse RD_HILO) */
#define MOD_a WR_a|RD_a
#define DSP_VOLA INSN_NO_DELAY_SLOT
-#define D32 ASE_DSP
-#define D33 ASE_DSPR2
-#define D64 ASE_DSP64
+#define D32 AFL_ASE_DSP
+#define D33 AFL_ASE_DSPR2
+#define D64 AFL_ASE_DSP64
/* MIPS MT ASE support. */
-#define MT32 ASE_MT
+#define MT32 AFL_ASE_MT
/* MIPS MCU (MicroController) ASE support. */
-#define MC ASE_MCU
+#define MC AFL_ASE_MCU
/* MIPS Enhanced VA Scheme. */
-#define EVA ASE_EVA
+#define EVA AFL_ASE_EVA
/* TLB invalidate instruction support. */
-#define TLBINV ASE_EVA
+#define TLBINV AFL_ASE_EVA
/* MSA support. */
-#define MSA ASE_MSA
-#define MSA64 ASE_MSA64
+#define MSA AFL_ASE_MSA
+#define MSA64 AFL_ASE_MSA64
/* eXtended Physical Address (XPA) support. */
-#define XPA ASE_XPA
+#define XPA AFL_ASE_XPA
/* The order of overloaded instructions matters. Label arguments and
register arguments look the same. Instructions that can have either
--
1.7.12