aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimir Radosavljevic <Vladimir.Radosavljevic@imgtec.com>2016-06-10 15:50:13 -0700
committerCary Coutant <ccoutant@gmail.com>2016-06-11 10:09:59 -0700
commitb52717c0e104eb603e8189c3c0d3658ef5d903f5 (patch)
treef487f184c07823ae523c1f825ce8d5deaaea3161
parent0eaf2e1b589472d635e85d2ce708faa35a23a90a (diff)
downloadgdb-b52717c0e104eb603e8189c3c0d3658ef5d903f5.zip
gdb-b52717c0e104eb603e8189c3c0d3658ef5d903f5.tar.gz
gdb-b52717c0e104eb603e8189c3c0d3658ef5d903f5.tar.bz2
Add support for .MIPS.abiflags and .gnu.attributes sections.
elfcpp/ * elfcpp.h (SHT_MIPS_ABIFLAGS): New enum constant. * mips.h (EF_MIPS_FP64, EF_MIPS_NAN2008): New enum constants for processor-specific flags. (E_MIPS_MACH_5900): New enum constant for machine variant. (AFL_REG_NONE, AFL_REG_32, AFL_REG_64, AFL_REG_128): New enum constants. (AFL_ASE_DSP, AFL_ASE_DSPR2, AFL_ASE_EVA, AFL_ASE_MCU, AFL_ASE_MDMX, AFL_ASE_MIPS3D, AFL_ASE_MT, AFL_ASE_SMARTMIPS, AFL_ASE_VIRT, AFL_ASE_MSA, AFL_ASE_MIPS16, AFL_ASE_MICROMIPS, AFL_ASE_XPA): Likewise. (AFL_EXT_XLR, AFL_EXT_OCTEON2, AFL_EXT_OCTEONP, AFL_EXT_LOONGSON_3A, AFL_EXT_OCTEON, AFL_EXT_5900, AFL_EXT_4650, AFL_EXT_4010, AFL_EXT_4100, AFL_EXT_3900, AFL_EXT_10000, AFL_EXT_SB1, AFL_EXT_4111, AFL_EXT_4120, AFL_EXT_5400, AFL_EXT_5500, AFL_EXT_LOONGSON_2E, AFL_EXT_LOONGSON_2F, AFL_EXT_OCTEON3): Likewise. (Tag_GNU_MIPS_ABI_FP, Tag_GNU_MIPS_ABI_MSA): Likewise. (Val_GNU_MIPS_ABI_FP_ANY, Val_GNU_MIPS_ABI_FP_DOUBLE, Val_GNU_MIPS_ABI_FP_SINGLE, Val_GNU_MIPS_ABI_FP_SOFT, Val_GNU_MIPS_ABI_FP_OLD_64,Val_GNU_MIPS_ABI_FP_XX, Val_GNU_MIPS_ABI_FP_64, Val_GNU_MIPS_ABI_FP_64A, Val_GNU_MIPS_ABI_FP_NAN2008, Val_GNU_MIPS_ABI_MSA_ANY, Val_GNU_MIPS_ABI_MSA_128): Likewise. (AFL_FLAGS1_ODDSPREG): New enum constant. gold/ * mips.cc (struct Mips_abiflags): New struct. (Mips_relobj::Mips_relobj): Initialize attributes_section_data_ and abiflags_. (Mips_relobj::~Mips_relobj): Delete object pointed by attributes_section_data_. (Mips_relobj::abiflags): New method. (Mips_relobj::attributes_section_data): Likewise. (Mips_relobj::attributes_section_data_): New data member. (Mips_relobj::abiflags_): Likewise. (class Mips_output_section_abiflags): New class. (Target_mips::Target_mips): Initialize attributes_section_data_, abiflags_ and has_abiflags_section_. (Target_mips::do_should_include_section): Don't emit input .MIPS.abiflags sections to output .MIPS.abiflags. (Target_mips::Mips_mach): Add new enum constants. (Target_mips::mips_isa_ext_mach): New method. (Target_mips::mips_isa_ext): Likewise. (Target_mips::update_abiflags_isa): Likewise. (Target_mips::infer_abiflags): Likewise. (Target_mips::create_abiflags): Likewise. (Target_mips::fp_abi_string): Likewise. (Target_mips::select_fp_abi): Likewise. (Target_mips::merge_obj_attributes): Likewise. (Target_mips::merge_obj_abiflags): Likewise. (Target_mips::level_rev): Likewise. (Target_mips::merge_obj_e_flags): Rename from merge_processor_specific_flags. Remove dyn_obj argument, call update_abiflags_isa when needed, compare NaN encodings and compare FP64 state. (Target_mips::add_machine_extensions): Add two machine extensions and fix one. (Target_mips::attributes_section_data_): New data member. (Target_mips::abiflags_): Likewise. (Target_mips::has_abiflags_section_): Likewise. (Mips_relobj::do_read_symbols): Read .gnu.attributes and .MIPS.abiflags sections if they exists. (Target_mips::elf_mips_mach): Add E_MIPS_MACH_5900 and E_MIPS_MACH_OCTEON3 support. (Target_mips::do_adjust_elf_header): Setup EI_ABIVERSION flag. (Target_mips::do_finalize_sections): Merge .gnu.attributes and .MIPS.abiflags sections from input. Create these sections if needed. (Target_mips::elf_mips_mach_name): Add E_MIPS_MACH_5900 and E_MIPS_MACH_OCTEON3 support, and change strings for E_MIPS_MACH_LS2E, E_MIPS_MACH_LS2F and E_MIPS_MACH_LS3A just to match bfd.
-rw-r--r--elfcpp/ChangeLog27
-rw-r--r--elfcpp/elfcpp.h2
-rw-r--r--elfcpp/mips.h140
-rw-r--r--gold/ChangeLog49
-rw-r--r--gold/mips.cc832
5 files changed, 988 insertions, 62 deletions
diff --git a/elfcpp/ChangeLog b/elfcpp/ChangeLog
index a469f86..93b2189 100644
--- a/elfcpp/ChangeLog
+++ b/elfcpp/ChangeLog
@@ -1,3 +1,30 @@
+2016-06-10 Vladimir Radosavljevic <Vladimir.Radosavljevic@imgtec.com>
+
+ * elfcpp.h (SHT_MIPS_ABIFLAGS): New enum constant.
+ * mips.h (EF_MIPS_FP64, EF_MIPS_NAN2008): New enum constants for
+ processor-specific flags.
+ (E_MIPS_MACH_5900): New enum constant for machine variant.
+ (AFL_REG_NONE, AFL_REG_32, AFL_REG_64, AFL_REG_128): New enum
+ constants.
+ (AFL_ASE_DSP, AFL_ASE_DSPR2, AFL_ASE_EVA, AFL_ASE_MCU,
+ AFL_ASE_MDMX, AFL_ASE_MIPS3D, AFL_ASE_MT, AFL_ASE_SMARTMIPS,
+ AFL_ASE_VIRT, AFL_ASE_MSA, AFL_ASE_MIPS16, AFL_ASE_MICROMIPS,
+ AFL_ASE_XPA): Likewise.
+ (AFL_EXT_XLR, AFL_EXT_OCTEON2, AFL_EXT_OCTEONP,
+ AFL_EXT_LOONGSON_3A, AFL_EXT_OCTEON, AFL_EXT_5900, AFL_EXT_4650,
+ AFL_EXT_4010, AFL_EXT_4100, AFL_EXT_3900, AFL_EXT_10000,
+ AFL_EXT_SB1, AFL_EXT_4111, AFL_EXT_4120, AFL_EXT_5400,
+ AFL_EXT_5500, AFL_EXT_LOONGSON_2E, AFL_EXT_LOONGSON_2F,
+ AFL_EXT_OCTEON3): Likewise.
+ (Tag_GNU_MIPS_ABI_FP, Tag_GNU_MIPS_ABI_MSA): Likewise.
+ (Val_GNU_MIPS_ABI_FP_ANY, Val_GNU_MIPS_ABI_FP_DOUBLE,
+ Val_GNU_MIPS_ABI_FP_SINGLE, Val_GNU_MIPS_ABI_FP_SOFT,
+ Val_GNU_MIPS_ABI_FP_OLD_64,Val_GNU_MIPS_ABI_FP_XX,
+ Val_GNU_MIPS_ABI_FP_64, Val_GNU_MIPS_ABI_FP_64A,
+ Val_GNU_MIPS_ABI_FP_NAN2008, Val_GNU_MIPS_ABI_MSA_ANY,
+ Val_GNU_MIPS_ABI_MSA_128): Likewise.
+ (AFL_FLAGS1_ODDSPREG): New enum constant.
+
2016-03-18 Vladimir Radosavljevic <vladimir.radosavljevic@imgtec.com>
* mips.h (abi_64): Remove.
diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h
index 3d7039a..f39a135 100644
--- a/elfcpp/elfcpp.h
+++ b/elfcpp/elfcpp.h
@@ -406,6 +406,8 @@ enum SHT
SHT_MIPS_REGINFO = 0x70000006,
// Section contains miscellaneous options.
SHT_MIPS_OPTIONS = 0x7000000d,
+ // ABI related flags section.
+ SHT_MIPS_ABIFLAGS = 0x7000002a,
// AARCH64-specific section type.
SHT_AARCH64_ATTRIBUTES = 0x70000003,
diff --git a/elfcpp/mips.h b/elfcpp/mips.h
index 10137ec..a7a9799 100644
--- a/elfcpp/mips.h
+++ b/elfcpp/mips.h
@@ -193,6 +193,10 @@ enum
// Indicates code compiled for a 64-bit machine in 32-bit mode.
// (regs are 32-bits wide.)
EF_MIPS_32BITMODE = 0x00000100,
+ // 32-bit machine but FP registers are 64 bit (-mfp64).
+ EF_MIPS_FP64 = 0x00000200,
+ /// Code in file uses the IEEE 754-2008 NaN encoding convention.
+ EF_MIPS_NAN2008 = 0x00000400,
// MIPS dynamic
EF_MIPS_DYNAMIC = 0x40
};
@@ -220,6 +224,7 @@ enum
E_MIPS_MACH_OCTEON2 = 0x008d0000,
E_MIPS_MACH_OCTEON3 = 0x008e0000,
E_MIPS_MACH_5400 = 0x00910000,
+ E_MIPS_MACH_5900 = 0x00920000,
E_MIPS_MACH_5500 = 0x00980000,
E_MIPS_MACH_9000 = 0x00990000,
E_MIPS_MACH_LS2E = 0x00A00000,
@@ -256,6 +261,141 @@ enum
E_MIPS_ARCH_64R6 = 0xa0000000,
};
+// Values for the xxx_size bytes of an ABI flags structure.
+enum
+{
+ // No registers.
+ AFL_REG_NONE = 0x00,
+ // 32-bit registers.
+ AFL_REG_32 = 0x01,
+ // 64-bit registers.
+ AFL_REG_64 = 0x02,
+ // 128-bit registers.
+ AFL_REG_128 = 0x03
+};
+
+// Masks for the ases word of an ABI flags structure.
+enum
+{
+ // DSP ASE.
+ AFL_ASE_DSP = 0x00000001,
+ // DSP R2 ASE.
+ AFL_ASE_DSPR2 = 0x00000002,
+ // Enhanced VA Scheme.
+ AFL_ASE_EVA = 0x00000004,
+ // MCU (MicroController) ASE.
+ AFL_ASE_MCU = 0x00000008,
+ // MDMX ASE.
+ AFL_ASE_MDMX = 0x00000010,
+ // MIPS-3D ASE.
+ AFL_ASE_MIPS3D = 0x00000020,
+ // MT ASE.
+ AFL_ASE_MT = 0x00000040,
+ // SmartMIPS ASE.
+ AFL_ASE_SMARTMIPS = 0x00000080,
+ // VZ ASE.
+ AFL_ASE_VIRT = 0x00000100,
+ // MSA ASE.
+ AFL_ASE_MSA = 0x00000200,
+ // MIPS16 ASE.
+ AFL_ASE_MIPS16 = 0x00000400,
+ // MICROMIPS ASE.
+ AFL_ASE_MICROMIPS = 0x00000800,
+ // XPA ASE.
+ AFL_ASE_XPA = 0x00001000
+};
+
+// Values for the isa_ext word of an ABI flags structure.
+enum
+{
+ // RMI Xlr instruction.
+ AFL_EXT_XLR = 1,
+ // Cavium Networks Octeon2.
+ AFL_EXT_OCTEON2 = 2,
+ // Cavium Networks OcteonP.
+ AFL_EXT_OCTEONP = 3,
+ // Loongson 3A.
+ AFL_EXT_LOONGSON_3A = 4,
+ // Cavium Networks Octeon.
+ AFL_EXT_OCTEON = 5,
+ // MIPS R5900 instruction.
+ AFL_EXT_5900 = 6,
+ // MIPS R4650 instruction.
+ AFL_EXT_4650 = 7,
+ // LSI R4010 instruction.
+ AFL_EXT_4010 = 8,
+ // NEC VR4100 instruction.
+ AFL_EXT_4100 = 9,
+ // Toshiba R3900 instruction.
+ AFL_EXT_3900 = 10,
+ // MIPS R10000 instruction.
+ AFL_EXT_10000 = 11,
+ // Broadcom SB-1 instruction.
+ AFL_EXT_SB1 = 12,
+ // NEC VR4111/VR4181 instruction.
+ AFL_EXT_4111 = 13,
+ // NEC VR4120 instruction.
+ AFL_EXT_4120 = 14,
+ // NEC VR5400 instruction.
+ AFL_EXT_5400 = 15,
+ // NEC VR5500 instruction.
+ AFL_EXT_5500 = 16,
+ // ST Microelectronics Loongson 2E.
+ AFL_EXT_LOONGSON_2E = 17,
+ // ST Microelectronics Loongson 2F.
+ AFL_EXT_LOONGSON_2F = 18,
+ // Cavium Networks Octeon3.
+ AFL_EXT_OCTEON3 = 19
+};
+
+// Masks for the flags1 word of an ABI flags structure.
+enum
+{
+ // Uses odd single-precision registers.
+ AFL_FLAGS1_ODDSPREG = 1
+};
+
+// Object attribute tags.
+enum
+{
+ // 0-3 are generic.
+ // Floating-point ABI used by this object file.
+ Tag_GNU_MIPS_ABI_FP = 4,
+ // MSA ABI used by this object file.
+ Tag_GNU_MIPS_ABI_MSA = 8
+};
+
+// Object attribute values.
+enum
+{
+ // Values defined for Tag_GNU_MIPS_ABI_FP.
+ // Not tagged or not using any ABIs affected by the differences.
+ Val_GNU_MIPS_ABI_FP_ANY = 0,
+ // Using hard-float -mdouble-float.
+ Val_GNU_MIPS_ABI_FP_DOUBLE = 1,
+ // Using hard-float -msingle-float.
+ Val_GNU_MIPS_ABI_FP_SINGLE = 2,
+ // Using soft-float.
+ Val_GNU_MIPS_ABI_FP_SOFT = 3,
+ // Using -mips32r2 -mfp64.
+ 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,
+ // Using -mips32r2 -mfp64 -mno-odd-spreg.
+ Val_GNU_MIPS_ABI_FP_64A = 7,
+ // This is reserved for backward-compatibility with an earlier
+ // implementation of the MIPS NaN2008 functionality.
+ Val_GNU_MIPS_ABI_FP_NAN2008 = 8,
+
+ // Values defined for Tag_GNU_MIPS_ABI_MSA.
+ // Not tagged or not using any ABIs affected by the differences.
+ Val_GNU_MIPS_ABI_MSA_ANY = 0,
+ // Using 128-bit MSA.
+ Val_GNU_MIPS_ABI_MSA_128 = 1
+};
+
enum
{
// Mask to extract ABI version, not really a flag value.
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 9552d55..c1b833b 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,5 +1,54 @@
2016-06-10 Vladimir Radosavljevic <Vladimir.Radosavljevic@imgtec.com>
+ * mips.cc (struct Mips_abiflags): New struct.
+ (Mips_relobj::Mips_relobj): Initialize attributes_section_data_
+ and abiflags_.
+ (Mips_relobj::~Mips_relobj): Delete object pointed by
+ attributes_section_data_.
+ (Mips_relobj::abiflags): New method.
+ (Mips_relobj::attributes_section_data): Likewise.
+ (Mips_relobj::attributes_section_data_): New data member.
+ (Mips_relobj::abiflags_): Likewise.
+ (class Mips_output_section_abiflags): New class.
+ (Target_mips::Target_mips): Initialize attributes_section_data_,
+ abiflags_ and has_abiflags_section_.
+ (Target_mips::do_should_include_section): Don't emit input
+ .MIPS.abiflags sections to output .MIPS.abiflags.
+ (Target_mips::Mips_mach): Add new enum constants.
+ (Target_mips::mips_isa_ext_mach): New method.
+ (Target_mips::mips_isa_ext): Likewise.
+ (Target_mips::update_abiflags_isa): Likewise.
+ (Target_mips::infer_abiflags): Likewise.
+ (Target_mips::create_abiflags): Likewise.
+ (Target_mips::fp_abi_string): Likewise.
+ (Target_mips::select_fp_abi): Likewise.
+ (Target_mips::merge_obj_attributes): Likewise.
+ (Target_mips::merge_obj_abiflags): Likewise.
+ (Target_mips::level_rev): Likewise.
+ (Target_mips::merge_obj_e_flags): Rename from
+ merge_processor_specific_flags. Remove dyn_obj argument,
+ call update_abiflags_isa when needed, compare NaN encodings and
+ compare FP64 state.
+ (Target_mips::add_machine_extensions): Add two machine extensions
+ and fix one.
+ (Target_mips::attributes_section_data_): New data member.
+ (Target_mips::abiflags_): Likewise.
+ (Target_mips::has_abiflags_section_): Likewise.
+ (Mips_relobj::do_read_symbols): Read .gnu.attributes and
+ .MIPS.abiflags sections if they exists.
+ (Target_mips::elf_mips_mach): Add E_MIPS_MACH_5900 and
+ E_MIPS_MACH_OCTEON3 support.
+ (Target_mips::do_adjust_elf_header): Setup EI_ABIVERSION flag.
+ (Target_mips::do_finalize_sections): Merge .gnu.attributes and
+ .MIPS.abiflags sections from input. Create these sections if
+ needed.
+ (Target_mips::elf_mips_mach_name): Add E_MIPS_MACH_5900 and
+ E_MIPS_MACH_OCTEON3 support, and change strings for
+ E_MIPS_MACH_LS2E, E_MIPS_MACH_LS2F and E_MIPS_MACH_LS3A just
+ to match bfd.
+
+2016-06-10 Vladimir Radosavljevic <Vladimir.Radosavljevic@imgtec.com>
+
* mips.cc (Mips_relobj::Mips_relobj): Initialize
has_reginfo_section_.
(Mips_relobj::has_reginfo_section_): New data member.
diff --git a/gold/mips.cc b/gold/mips.cc
index 59ce88e..42ec64b 100644
--- a/gold/mips.cc
+++ b/gold/mips.cc
@@ -44,6 +44,7 @@
#include "tls.h"
#include "errors.h"
#include "gc.h"
+#include "attributes.h"
#include "nacl.h"
namespace
@@ -954,6 +955,43 @@ struct got16_addend
Mips_address addend;
};
+// .MIPS.abiflags section content
+
+template<bool big_endian>
+struct Mips_abiflags
+{
+ typedef typename elfcpp::Swap<8, big_endian>::Valtype Valtype8;
+ typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype16;
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype32;
+
+ Mips_abiflags()
+ : version(0), isa_level(0), isa_rev(0), gpr_size(0), cpr1_size(0),
+ cpr2_size(0), fp_abi(0), isa_ext(0), ases(0), flags1(0), flags2(0)
+ { }
+
+ // Version of flags structure.
+ Valtype16 version;
+ // The level of the ISA: 1-5, 32, 64.
+ Valtype8 isa_level;
+ // The revision of ISA: 0 for MIPS V and below, 1-n otherwise.
+ Valtype8 isa_rev;
+ // The size of general purpose registers.
+ Valtype8 gpr_size;
+ // The size of co-processor 1 registers.
+ Valtype8 cpr1_size;
+ // The size of co-processor 2 registers.
+ Valtype8 cpr2_size;
+ // The floating-point ABI.
+ Valtype8 fp_abi;
+ // Processor-specific extension.
+ Valtype32 isa_ext;
+ // Mask of ASEs used.
+ Valtype32 ases;
+ // Mask of general flags.
+ Valtype32 flags1;
+ Valtype32 flags2;
+};
+
// Mips_symbol class. Holds additional symbol information needed for Mips.
template<int size>
@@ -1547,15 +1585,15 @@ class Mips_relobj : public Sized_relobj_file<size, big_endian>
local_mips16_call_stubs_(), gp_(0), has_reginfo_section_(false),
got_info_(NULL), section_is_mips16_fn_stub_(),
section_is_mips16_call_stub_(), section_is_mips16_call_fp_stub_(),
- pdr_shndx_(-1U), gprmask_(0), cprmask1_(0), cprmask2_(0), cprmask3_(0),
- cprmask4_(0)
+ pdr_shndx_(-1U), attributes_section_data_(NULL), abiflags_(NULL),
+ gprmask_(0), cprmask1_(0), cprmask2_(0), cprmask3_(0), cprmask4_(0)
{
this->is_pic_ = (ehdr.get_e_flags() & elfcpp::EF_MIPS_PIC) != 0;
this->is_n32_ = elfcpp::abi_n32(ehdr.get_e_flags());
}
~Mips_relobj()
- { }
+ { delete this->attributes_section_data_; }
// Downcast a base pointer to a Mips_relobj pointer. This is
// not type-safe but we only use Mips_relobj not the base class.
@@ -1814,6 +1852,16 @@ class Mips_relobj : public Sized_relobj_file<size, big_endian>
cprmask4() const
{ return this->cprmask4_; }
+ // This is the contents of the .MIPS.abiflags section if there is one.
+ Mips_abiflags<big_endian>*
+ abiflags()
+ { return this->abiflags_; }
+
+ // This is the contents of the .gnu.attribute section if there is one.
+ const Attributes_section_data*
+ attributes_section_data() const
+ { return this->attributes_section_data_; }
+
protected:
// Count the local symbols.
void
@@ -1887,6 +1935,12 @@ class Mips_relobj : public Sized_relobj_file<size, big_endian>
// .pdr section index.
unsigned int pdr_shndx_;
+ // Object attributes if there is a .gnu.attributes section or NULL.
+ Attributes_section_data* attributes_section_data_;
+
+ // Object abiflags if there is a .MIPS.abiflags section or NULL.
+ Mips_abiflags<big_endian>* abiflags_;
+
// gprmask from the .reginfo section of this object.
Valtype gprmask_;
// cprmask1 from the .reginfo section of this object.
@@ -2760,6 +2814,29 @@ class Mips_output_section_reginfo : public Output_section_data
Valtype cprmask4_;
};
+// This class handles .MIPS.abiflags output section.
+
+template<int size, bool big_endian>
+class Mips_output_section_abiflags : public Output_section_data
+{
+ public:
+ Mips_output_section_abiflags(const Mips_abiflags<big_endian>& abiflags)
+ : Output_section_data(24, 8, true), abiflags_(abiflags)
+ { }
+
+ protected:
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _(".MIPS.abiflags")); }
+
+ void
+ do_write(Output_file* of);
+
+ private:
+ const Mips_abiflags<big_endian>& abiflags_;
+};
+
// The MIPS target has relocation types which default handling of relocatable
// relocation cannot process. So we have to extend the default code.
@@ -3208,9 +3285,10 @@ class Target_mips : public Sized_target<size, big_endian>
public:
Target_mips(const Target::Target_info* info = &mips_info)
: Sized_target<size, big_endian>(info), got_(NULL), gp_(NULL), plt_(NULL),
- got_plt_(NULL), rel_dyn_(NULL), copy_relocs_(),
- dyn_relocs_(), la25_stub_(NULL), mips_mach_extensions_(),
- mips_stubs_(NULL), mach_(0), layout_(NULL), got16_addends_(),
+ got_plt_(NULL), rel_dyn_(NULL), copy_relocs_(), dyn_relocs_(),
+ la25_stub_(NULL), mips_mach_extensions_(), mips_stubs_(NULL),
+ attributes_section_data_(NULL), abiflags_(NULL), mach_(0), layout_(NULL),
+ got16_addends_(), has_abiflags_section_(false),
entry_symbol_is_compressed_(false), insn32_(false)
{
this->add_machine_extensions();
@@ -3441,10 +3519,14 @@ class Target_mips : public Sized_target<size, big_endian>
do_has_custom_set_dynsym_indexes() const
{ return true; }
- // Don't emit input .reginfo sections to output .reginfo.
+ // Don't emit input .reginfo/.MIPS.abiflags sections to
+ // output .reginfo/.MIPS.abiflags.
bool
do_should_include_section(elfcpp::Elf_Word sh_type) const
- { return sh_type != elfcpp::SHT_MIPS_REGINFO; }
+ {
+ return ((sh_type != elfcpp::SHT_MIPS_REGINFO)
+ && (sh_type != elfcpp::SHT_MIPS_ABIFLAGS));
+ }
// Set the dynamic symbol indexes. INDEX is the index of the first
// global dynamic symbol. Pointers to the symbols are stored into the
@@ -3476,7 +3558,7 @@ class Target_mips : public Sized_target<size, big_endian>
}
// Whether the output has microMIPS code. This is valid only after
- // merge_processor_specific_flags() is called.
+ // merge_obj_e_flags() is called.
bool
is_output_micromips() const
{
@@ -3485,7 +3567,7 @@ class Target_mips : public Sized_target<size, big_endian>
}
// Whether the output uses N32 ABI. This is valid only after
- // merge_processor_specific_flags() is called.
+ // merge_obj_e_flags() is called.
bool
is_output_n32() const
{
@@ -3499,7 +3581,7 @@ class Target_mips : public Sized_target<size, big_endian>
{ return size == 64; }
// Whether the output uses NEWABI. This is valid only after
- // merge_processor_specific_flags() is called.
+ // merge_obj_e_flags() is called.
bool
is_output_newabi() const
{ return this->is_output_n32() || this->is_output_n64(); }
@@ -3817,6 +3899,7 @@ class Target_mips : public Sized_target<size, big_endian>
mach_mips5000 = 5000,
mach_mips5400 = 5400,
mach_mips5500 = 5500,
+ mach_mips5900 = 5900,
mach_mips6000 = 6000,
mach_mips7000 = 7000,
mach_mips8000 = 8000,
@@ -3834,11 +3917,16 @@ class Target_mips : public Sized_target<size, big_endian>
mach_mips_octeon = 6501,
mach_mips_octeonp = 6601,
mach_mips_octeon2 = 6502,
+ mach_mips_octeon3 = 6503,
mach_mips_xlr = 887682, // decimal 'XLR'
mach_mipsisa32 = 32,
mach_mipsisa32r2 = 33,
+ mach_mipsisa32r3 = 34,
+ mach_mipsisa32r5 = 36,
mach_mipsisa64 = 64,
mach_mipsisa64r2 = 65,
+ mach_mipsisa64r3 = 66,
+ mach_mipsisa64r5 = 68,
mach_mips_micromips = 96
};
@@ -3846,13 +3934,55 @@ class Target_mips : public Sized_target<size, big_endian>
unsigned int
elf_mips_mach(elfcpp::Elf_Word);
+ // Return the MACH for each .MIPS.abiflags ISA Extension.
+ unsigned int
+ mips_isa_ext_mach(unsigned int);
+
+ // Return the .MIPS.abiflags value representing each ISA Extension.
+ unsigned int
+ mips_isa_ext(unsigned int);
+
+ // Update the isa_level, isa_rev, isa_ext fields of abiflags.
+ void
+ update_abiflags_isa(const std::string&, elfcpp::Elf_Word,
+ Mips_abiflags<big_endian>*);
+
+ // Infer the content of the ABI flags based on the elf header.
+ void
+ infer_abiflags(Mips_relobj<size, big_endian>*, Mips_abiflags<big_endian>*);
+
+ // Create abiflags from elf header or from .MIPS.abiflags section.
+ void
+ create_abiflags(Mips_relobj<size, big_endian>*, Mips_abiflags<big_endian>*);
+
+ // Return the meaning of fp_abi, or "unknown" if not known.
+ const char*
+ fp_abi_string(int);
+
+ // Select fp_abi.
+ int
+ select_fp_abi(const std::string&, int, int);
+
+ // Merge attributes from input object.
+ void
+ merge_obj_attributes(const std::string&, const Attributes_section_data*);
+
+ // Merge abiflags from input object.
+ void
+ merge_obj_abiflags(const std::string&, Mips_abiflags<big_endian>*);
+
// Check whether machine EXTENSION is an extension of machine BASE.
bool
mips_mach_extends(unsigned int, unsigned int);
- // Merge processor specific flags.
+ // Merge file header flags from input object.
void
- merge_processor_specific_flags(const std::string&, elfcpp::Elf_Word, bool);
+ merge_obj_e_flags(const std::string&, elfcpp::Elf_Word);
+
+ // Encode ISA level and revision as a single value.
+ int
+ level_rev(unsigned char isa_level, unsigned char isa_rev) const
+ { return (isa_level << 3) | isa_rev; }
// True if we are linking for CPUs that are faster if JAL is converted to BAL.
static inline bool
@@ -3942,15 +4072,16 @@ class Target_mips : public Sized_target<size, big_endian>
add_machine_extensions()
{
// MIPS64r2 extensions.
+ this->add_extension(mach_mips_octeon3, mach_mips_octeon2);
this->add_extension(mach_mips_octeon2, mach_mips_octeonp);
this->add_extension(mach_mips_octeonp, mach_mips_octeon);
this->add_extension(mach_mips_octeon, mach_mipsisa64r2);
+ this->add_extension(mach_mips_loongson_3a, mach_mipsisa64r2);
// MIPS64 extensions.
this->add_extension(mach_mipsisa64r2, mach_mipsisa64);
this->add_extension(mach_mips_sb1, mach_mipsisa64);
this->add_extension(mach_mips_xlr, mach_mipsisa64);
- this->add_extension(mach_mips_loongson_3a, mach_mipsisa64);
// MIPS V extensions.
this->add_extension(mach_mipsisa64, mach_mips5);
@@ -3989,6 +4120,7 @@ class Target_mips : public Sized_target<size, big_endian>
this->add_extension(mach_mips4300, mach_mips4000);
this->add_extension(mach_mips4100, mach_mips4000);
this->add_extension(mach_mips4010, mach_mips4000);
+ this->add_extension(mach_mips5900, mach_mips4000);
// MIPS32 extensions.
this->add_extension(mach_mipsisa32r2, mach_mipsisa32);
@@ -4044,11 +4176,19 @@ class Target_mips : public Sized_target<size, big_endian>
// .MIPS.stubs
Mips_output_data_mips_stubs<size, big_endian>* mips_stubs_;
+ // Attributes section data in output.
+ Attributes_section_data* attributes_section_data_;
+ // .MIPS.abiflags section data in output.
+ Mips_abiflags<big_endian>* abiflags_;
+
unsigned int mach_;
Layout* layout_;
typename std::list<got16_addend<size, big_endian> > got16_addends_;
+ // Whether there is an input .MIPS.abiflags section.
+ bool has_abiflags_section_;
+
// Whether the entry symbol is mips16 or micromips.
bool entry_symbol_is_compressed_;
@@ -6401,6 +6541,60 @@ Mips_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
this->cprmask4_ = elfcpp::Swap<size, big_endian>::readval(view + 16);
}
+ if (shdr.get_sh_type() == elfcpp::SHT_GNU_ATTRIBUTES)
+ {
+ gold_assert(this->attributes_section_data_ == NULL);
+ section_offset_type section_offset = shdr.get_sh_offset();
+ section_size_type section_size =
+ convert_to_section_size_type(shdr.get_sh_size());
+ const unsigned char* view =
+ this->get_view(section_offset, section_size, true, false);
+ this->attributes_section_data_ =
+ new Attributes_section_data(view, section_size);
+ }
+
+ if (shdr.get_sh_type() == elfcpp::SHT_MIPS_ABIFLAGS)
+ {
+ gold_assert(this->abiflags_ == NULL);
+ section_offset_type section_offset = shdr.get_sh_offset();
+ section_size_type section_size =
+ convert_to_section_size_type(shdr.get_sh_size());
+ const unsigned char* view =
+ this->get_view(section_offset, section_size, true, false);
+ this->abiflags_ = new Mips_abiflags<big_endian>();
+
+ this->abiflags_->version =
+ elfcpp::Swap<16, big_endian>::readval(view);
+ if (this->abiflags_->version != 0)
+ {
+ gold_error(_("%s: .MIPS.abiflags section has "
+ "unsupported version %u"),
+ this->name().c_str(),
+ this->abiflags_->version);
+ break;
+ }
+ this->abiflags_->isa_level =
+ elfcpp::Swap<8, big_endian>::readval(view + 2);
+ this->abiflags_->isa_rev =
+ elfcpp::Swap<8, big_endian>::readval(view + 3);
+ this->abiflags_->gpr_size =
+ elfcpp::Swap<8, big_endian>::readval(view + 4);
+ this->abiflags_->cpr1_size =
+ elfcpp::Swap<8, big_endian>::readval(view + 5);
+ this->abiflags_->cpr2_size =
+ elfcpp::Swap<8, big_endian>::readval(view + 6);
+ this->abiflags_->fp_abi =
+ elfcpp::Swap<8, big_endian>::readval(view + 7);
+ this->abiflags_->isa_ext =
+ elfcpp::Swap<32, big_endian>::readval(view + 8);
+ this->abiflags_->ases =
+ elfcpp::Swap<32, big_endian>::readval(view + 12);
+ this->abiflags_->flags1 =
+ elfcpp::Swap<32, big_endian>::readval(view + 16);
+ this->abiflags_->flags2 =
+ elfcpp::Swap<32, big_endian>::readval(view + 20);
+ }
+
// In the 64-bit ABI, .MIPS.options section holds register information.
// A SHT_MIPS_OPTIONS section contains a series of options, each of which
// starts with this header:
@@ -7694,6 +7888,31 @@ Mips_output_section_reginfo<size, big_endian>::do_write(Output_file* of)
of->write_output_view(offset, data_size, view);
}
+// Mips_output_section_abiflags methods.
+
+template<int size, bool big_endian>
+void
+Mips_output_section_abiflags<size, big_endian>::do_write(Output_file* of)
+{
+ off_t offset = this->offset();
+ off_t data_size = this->data_size();
+
+ unsigned char* view = of->get_output_view(offset, data_size);
+ elfcpp::Swap<16, big_endian>::writeval(view, this->abiflags_.version);
+ elfcpp::Swap<8, big_endian>::writeval(view + 2, this->abiflags_.isa_level);
+ elfcpp::Swap<8, big_endian>::writeval(view + 3, this->abiflags_.isa_rev);
+ elfcpp::Swap<8, big_endian>::writeval(view + 4, this->abiflags_.gpr_size);
+ elfcpp::Swap<8, big_endian>::writeval(view + 5, this->abiflags_.cpr1_size);
+ elfcpp::Swap<8, big_endian>::writeval(view + 6, this->abiflags_.cpr2_size);
+ elfcpp::Swap<8, big_endian>::writeval(view + 7, this->abiflags_.fp_abi);
+ elfcpp::Swap<32, big_endian>::writeval(view + 8, this->abiflags_.isa_ext);
+ elfcpp::Swap<32, big_endian>::writeval(view + 12, this->abiflags_.ases);
+ elfcpp::Swap<32, big_endian>::writeval(view + 16, this->abiflags_.flags1);
+ elfcpp::Swap<32, big_endian>::writeval(view + 20, this->abiflags_.flags2);
+
+ of->write_output_view(offset, data_size, view);
+}
+
// Mips_copy_relocs methods.
// Emit any saved relocs.
@@ -8254,6 +8473,9 @@ Target_mips<size, big_endian>::elf_mips_mach(elfcpp::Elf_Word flags)
case elfcpp::E_MIPS_MACH_5500:
return mach_mips5500;
+ case elfcpp::E_MIPS_MACH_5900:
+ return mach_mips5900;
+
case elfcpp::E_MIPS_MACH_9000:
return mach_mips9000;
@@ -8269,6 +8491,9 @@ Target_mips<size, big_endian>::elf_mips_mach(elfcpp::Elf_Word flags)
case elfcpp::E_MIPS_MACH_LS3A:
return mach_mips_loongson_3a;
+ case elfcpp::E_MIPS_MACH_OCTEON3:
+ return mach_mips_octeon3;
+
case elfcpp::E_MIPS_MACH_OCTEON2:
return mach_mips_octeon2;
@@ -8314,6 +8539,426 @@ Target_mips<size, big_endian>::elf_mips_mach(elfcpp::Elf_Word flags)
return 0;
}
+// Return the MACH for each .MIPS.abiflags ISA Extension.
+
+template<int size, bool big_endian>
+unsigned int
+Target_mips<size, big_endian>::mips_isa_ext_mach(unsigned int isa_ext)
+{
+ switch (isa_ext)
+ {
+ case elfcpp::AFL_EXT_3900:
+ return mach_mips3900;
+
+ case elfcpp::AFL_EXT_4010:
+ return mach_mips4010;
+
+ case elfcpp::AFL_EXT_4100:
+ return mach_mips4100;
+
+ case elfcpp::AFL_EXT_4111:
+ return mach_mips4111;
+
+ case elfcpp::AFL_EXT_4120:
+ return mach_mips4120;
+
+ case elfcpp::AFL_EXT_4650:
+ return mach_mips4650;
+
+ case elfcpp::AFL_EXT_5400:
+ return mach_mips5400;
+
+ case elfcpp::AFL_EXT_5500:
+ return mach_mips5500;
+
+ case elfcpp::AFL_EXT_5900:
+ return mach_mips5900;
+
+ case elfcpp::AFL_EXT_10000:
+ return mach_mips10000;
+
+ case elfcpp::AFL_EXT_LOONGSON_2E:
+ return mach_mips_loongson_2e;
+
+ case elfcpp::AFL_EXT_LOONGSON_2F:
+ return mach_mips_loongson_2f;
+
+ case elfcpp::AFL_EXT_LOONGSON_3A:
+ return mach_mips_loongson_3a;
+
+ case elfcpp::AFL_EXT_SB1:
+ return mach_mips_sb1;
+
+ case elfcpp::AFL_EXT_OCTEON:
+ return mach_mips_octeon;
+
+ case elfcpp::AFL_EXT_OCTEONP:
+ return mach_mips_octeonp;
+
+ case elfcpp::AFL_EXT_OCTEON2:
+ return mach_mips_octeon2;
+
+ case elfcpp::AFL_EXT_XLR:
+ return mach_mips_xlr;
+
+ default:
+ return mach_mips3000;
+ }
+}
+
+// Return the .MIPS.abiflags value representing each ISA Extension.
+
+template<int size, bool big_endian>
+unsigned int
+Target_mips<size, big_endian>::mips_isa_ext(unsigned int mips_mach)
+{
+ switch (mips_mach)
+ {
+ case mach_mips3900:
+ return elfcpp::AFL_EXT_3900;
+
+ case mach_mips4010:
+ return elfcpp::AFL_EXT_4010;
+
+ case mach_mips4100:
+ return elfcpp::AFL_EXT_4100;
+
+ case mach_mips4111:
+ return elfcpp::AFL_EXT_4111;
+
+ case mach_mips4120:
+ return elfcpp::AFL_EXT_4120;
+
+ case mach_mips4650:
+ return elfcpp::AFL_EXT_4650;
+
+ case mach_mips5400:
+ return elfcpp::AFL_EXT_5400;
+
+ case mach_mips5500:
+ return elfcpp::AFL_EXT_5500;
+
+ case mach_mips5900:
+ return elfcpp::AFL_EXT_5900;
+
+ case mach_mips10000:
+ return elfcpp::AFL_EXT_10000;
+
+ case mach_mips_loongson_2e:
+ return elfcpp::AFL_EXT_LOONGSON_2E;
+
+ case mach_mips_loongson_2f:
+ return elfcpp::AFL_EXT_LOONGSON_2F;
+
+ case mach_mips_loongson_3a:
+ return elfcpp::AFL_EXT_LOONGSON_3A;
+
+ case mach_mips_sb1:
+ return elfcpp::AFL_EXT_SB1;
+
+ case mach_mips_octeon:
+ return elfcpp::AFL_EXT_OCTEON;
+
+ case mach_mips_octeonp:
+ return elfcpp::AFL_EXT_OCTEONP;
+
+ case mach_mips_octeon3:
+ return elfcpp::AFL_EXT_OCTEON3;
+
+ case mach_mips_octeon2:
+ return elfcpp::AFL_EXT_OCTEON2;
+
+ case mach_mips_xlr:
+ return elfcpp::AFL_EXT_XLR;
+
+ default:
+ return 0;
+ }
+}
+
+// Update the isa_level, isa_rev, isa_ext fields of abiflags.
+
+template<int size, bool big_endian>
+void
+Target_mips<size, big_endian>::update_abiflags_isa(const std::string& name,
+ elfcpp::Elf_Word e_flags, Mips_abiflags<big_endian>* abiflags)
+{
+ int new_isa = 0;
+ switch (e_flags & elfcpp::EF_MIPS_ARCH)
+ {
+ case elfcpp::E_MIPS_ARCH_1:
+ new_isa = this->level_rev(1, 0);
+ break;
+ case elfcpp::E_MIPS_ARCH_2:
+ new_isa = this->level_rev(2, 0);
+ break;
+ case elfcpp::E_MIPS_ARCH_3:
+ new_isa = this->level_rev(3, 0);
+ break;
+ case elfcpp::E_MIPS_ARCH_4:
+ new_isa = this->level_rev(4, 0);
+ break;
+ case elfcpp::E_MIPS_ARCH_5:
+ new_isa = this->level_rev(5, 0);
+ break;
+ case elfcpp::E_MIPS_ARCH_32:
+ new_isa = this->level_rev(32, 1);
+ break;
+ case elfcpp::E_MIPS_ARCH_32R2:
+ new_isa = this->level_rev(32, 2);
+ break;
+ case elfcpp::E_MIPS_ARCH_64:
+ new_isa = this->level_rev(64, 1);
+ break;
+ case elfcpp::E_MIPS_ARCH_64R2:
+ new_isa = this->level_rev(64, 2);
+ break;
+ default:
+ gold_error(_("%s: Unknown architecture %s"), name.c_str(),
+ this->elf_mips_mach_name(e_flags));
+ }
+
+ if (new_isa > this->level_rev(abiflags->isa_level, abiflags->isa_rev))
+ {
+ // Decode a single value into level and revision.
+ abiflags->isa_level = new_isa >> 3;
+ abiflags->isa_rev = new_isa & 0x7;
+ }
+
+ // Update the isa_ext if needed.
+ if (this->mips_mach_extends(this->mips_isa_ext_mach(abiflags->isa_ext),
+ this->elf_mips_mach(e_flags)))
+ abiflags->isa_ext = this->mips_isa_ext(this->elf_mips_mach(e_flags));
+}
+
+// Infer the content of the ABI flags based on the elf header.
+
+template<int size, bool big_endian>
+void
+Target_mips<size, big_endian>::infer_abiflags(
+ Mips_relobj<size, big_endian>* relobj, Mips_abiflags<big_endian>* abiflags)
+{
+ const Attributes_section_data* pasd = relobj->attributes_section_data();
+ int attr_fp_abi = elfcpp::Val_GNU_MIPS_ABI_FP_ANY;
+ elfcpp::Elf_Word e_flags = relobj->processor_specific_flags();
+
+ this->update_abiflags_isa(relobj->name(), e_flags, abiflags);
+ if (pasd != NULL)
+ {
+ // Read fp_abi from the .gnu.attribute section.
+ const Object_attribute* attr =
+ pasd->known_attributes(Object_attribute::OBJ_ATTR_GNU);
+ attr_fp_abi = attr[elfcpp::Tag_GNU_MIPS_ABI_FP].int_value();
+ }
+
+ abiflags->fp_abi = attr_fp_abi;
+ abiflags->cpr1_size = elfcpp::AFL_REG_NONE;
+ abiflags->cpr2_size = elfcpp::AFL_REG_NONE;
+ abiflags->gpr_size = this->mips_32bit_flags(e_flags) ? elfcpp::AFL_REG_32
+ : elfcpp::AFL_REG_64;
+
+ if (abiflags->fp_abi == elfcpp::Val_GNU_MIPS_ABI_FP_SINGLE
+ || abiflags->fp_abi == elfcpp::Val_GNU_MIPS_ABI_FP_XX
+ || (abiflags->fp_abi == elfcpp::Val_GNU_MIPS_ABI_FP_DOUBLE
+ && abiflags->gpr_size == elfcpp::AFL_REG_32))
+ abiflags->cpr1_size = elfcpp::AFL_REG_32;
+ else if (abiflags->fp_abi == elfcpp::Val_GNU_MIPS_ABI_FP_DOUBLE
+ || abiflags->fp_abi == elfcpp::Val_GNU_MIPS_ABI_FP_64
+ || abiflags->fp_abi == elfcpp::Val_GNU_MIPS_ABI_FP_64A)
+ abiflags->cpr1_size = elfcpp::AFL_REG_64;
+
+ if (e_flags & elfcpp::EF_MIPS_ARCH_ASE_MDMX)
+ abiflags->ases |= elfcpp::AFL_ASE_MDMX;
+ if (e_flags & elfcpp::EF_MIPS_ARCH_ASE_M16)
+ abiflags->ases |= elfcpp::AFL_ASE_MIPS16;
+ if (e_flags & elfcpp::EF_MIPS_ARCH_ASE_MICROMIPS)
+ abiflags->ases |= elfcpp::AFL_ASE_MICROMIPS;
+
+ if (abiflags->fp_abi != elfcpp::Val_GNU_MIPS_ABI_FP_ANY
+ && abiflags->fp_abi != elfcpp::Val_GNU_MIPS_ABI_FP_SOFT
+ && abiflags->fp_abi != elfcpp::Val_GNU_MIPS_ABI_FP_64A
+ && abiflags->isa_level >= 32
+ && abiflags->isa_ext != elfcpp::AFL_EXT_LOONGSON_3A)
+ abiflags->flags1 |= elfcpp::AFL_FLAGS1_ODDSPREG;
+}
+
+// Create abiflags from elf header or from .MIPS.abiflags section.
+
+template<int size, bool big_endian>
+void
+Target_mips<size, big_endian>::create_abiflags(
+ Mips_relobj<size, big_endian>* relobj,
+ Mips_abiflags<big_endian>* abiflags)
+{
+ Mips_abiflags<big_endian>* sec_abiflags = relobj->abiflags();
+ Mips_abiflags<big_endian> header_abiflags;
+
+ this->infer_abiflags(relobj, &header_abiflags);
+
+ if (sec_abiflags == NULL)
+ {
+ // If there is no input .MIPS.abiflags section, use abiflags created
+ // from elf header.
+ *abiflags = header_abiflags;
+ return;
+ }
+
+ this->has_abiflags_section_ = true;
+
+ // It is not possible to infer the correct ISA revision for R3 or R5
+ // so drop down to R2 for the checks.
+ unsigned char isa_rev = sec_abiflags->isa_rev;
+ if (isa_rev == 3 || isa_rev == 5)
+ isa_rev = 2;
+
+ // Check compatibility between abiflags created from elf header
+ // and abiflags from .MIPS.abiflags section in this object file.
+ if (this->level_rev(sec_abiflags->isa_level, isa_rev)
+ < this->level_rev(header_abiflags.isa_level, header_abiflags.isa_rev))
+ gold_warning(_("%s: Inconsistent ISA between e_flags and .MIPS.abiflags"),
+ relobj->name().c_str());
+ if (header_abiflags.fp_abi != elfcpp::Val_GNU_MIPS_ABI_FP_ANY
+ && sec_abiflags->fp_abi != header_abiflags.fp_abi)
+ gold_warning(_("%s: Inconsistent FP ABI between .gnu.attributes and "
+ ".MIPS.abiflags"), relobj->name().c_str());
+ if ((sec_abiflags->ases & header_abiflags.ases) != header_abiflags.ases)
+ gold_warning(_("%s: Inconsistent ASEs between e_flags and .MIPS.abiflags"),
+ relobj->name().c_str());
+ // The isa_ext is allowed to be an extension of what can be inferred
+ // from e_flags.
+ if (!this->mips_mach_extends(this->mips_isa_ext_mach(header_abiflags.isa_ext),
+ this->mips_isa_ext_mach(sec_abiflags->isa_ext)))
+ gold_warning(_("%s: Inconsistent ISA extensions between e_flags and "
+ ".MIPS.abiflags"), relobj->name().c_str());
+ if (sec_abiflags->flags2 != 0)
+ gold_warning(_("%s: Unexpected flag in the flags2 field of "
+ ".MIPS.abiflags (0x%x)"), relobj->name().c_str(),
+ sec_abiflags->flags2);
+ // Use abiflags from .MIPS.abiflags section.
+ *abiflags = *sec_abiflags;
+}
+
+// Return the meaning of fp_abi, or "unknown" if not known.
+
+template<int size, bool big_endian>
+const char*
+Target_mips<size, big_endian>::fp_abi_string(int fp)
+{
+ switch (fp)
+ {
+ case elfcpp::Val_GNU_MIPS_ABI_FP_DOUBLE:
+ return "-mdouble-float";
+ case elfcpp::Val_GNU_MIPS_ABI_FP_SINGLE:
+ return "-msingle-float";
+ case elfcpp::Val_GNU_MIPS_ABI_FP_SOFT:
+ return "-msoft-float";
+ case elfcpp::Val_GNU_MIPS_ABI_FP_OLD_64:
+ return _("-mips32r2 -mfp64 (12 callee-saved)");
+ case elfcpp::Val_GNU_MIPS_ABI_FP_XX:
+ return "-mfpxx";
+ case elfcpp::Val_GNU_MIPS_ABI_FP_64:
+ return "-mgp32 -mfp64";
+ case elfcpp::Val_GNU_MIPS_ABI_FP_64A:
+ return "-mgp32 -mfp64 -mno-odd-spreg";
+ default:
+ return "unknown";
+ }
+}
+
+// Select fp_abi.
+
+template<int size, bool big_endian>
+int
+Target_mips<size, big_endian>::select_fp_abi(const std::string& name, int in_fp,
+ int out_fp)
+{
+ if (in_fp == out_fp)
+ return out_fp;
+
+ if (out_fp == elfcpp::Val_GNU_MIPS_ABI_FP_ANY)
+ return in_fp;
+ else if (out_fp == elfcpp::Val_GNU_MIPS_ABI_FP_XX
+ && (in_fp == elfcpp::Val_GNU_MIPS_ABI_FP_DOUBLE
+ || in_fp == elfcpp::Val_GNU_MIPS_ABI_FP_64
+ || in_fp == elfcpp::Val_GNU_MIPS_ABI_FP_64A))
+ return in_fp;
+ else if (in_fp == elfcpp::Val_GNU_MIPS_ABI_FP_XX
+ && (out_fp == elfcpp::Val_GNU_MIPS_ABI_FP_DOUBLE
+ || out_fp == elfcpp::Val_GNU_MIPS_ABI_FP_64
+ || out_fp == elfcpp::Val_GNU_MIPS_ABI_FP_64A))
+ return out_fp; // Keep the current setting.
+ else if (out_fp == elfcpp::Val_GNU_MIPS_ABI_FP_64A
+ && in_fp == elfcpp::Val_GNU_MIPS_ABI_FP_64)
+ return in_fp;
+ else if (in_fp == elfcpp::Val_GNU_MIPS_ABI_FP_64A
+ && out_fp == elfcpp::Val_GNU_MIPS_ABI_FP_64)
+ return out_fp; // Keep the current setting.
+ else if (in_fp != elfcpp::Val_GNU_MIPS_ABI_FP_ANY)
+ gold_warning(_("%s: FP ABI %s is incompatible with %s"), name.c_str(),
+ fp_abi_string(in_fp), fp_abi_string(out_fp));
+ return out_fp;
+}
+
+// Merge attributes from input object.
+
+template<int size, bool big_endian>
+void
+Target_mips<size, big_endian>::merge_obj_attributes(const std::string& name,
+ const Attributes_section_data* pasd)
+{
+ // Return if there is no attributes section data.
+ if (pasd == NULL)
+ return;
+
+ // If output has no object attributes, just copy.
+ if (this->attributes_section_data_ == NULL)
+ {
+ this->attributes_section_data_ = new Attributes_section_data(*pasd);
+ return;
+ }
+
+ Object_attribute* out_attr = this->attributes_section_data_->known_attributes(
+ Object_attribute::OBJ_ATTR_GNU);
+
+ out_attr[elfcpp::Tag_GNU_MIPS_ABI_FP].set_type(1);
+ out_attr[elfcpp::Tag_GNU_MIPS_ABI_FP].set_int_value(this->abiflags_->fp_abi);
+
+ // Merge Tag_compatibility attributes and any common GNU ones.
+ this->attributes_section_data_->merge(name.c_str(), pasd);
+}
+
+// Merge abiflags from input object.
+
+template<int size, bool big_endian>
+void
+Target_mips<size, big_endian>::merge_obj_abiflags(const std::string& name,
+ Mips_abiflags<big_endian>* in_abiflags)
+{
+ // If output has no abiflags, just copy.
+ if (this->abiflags_ == NULL)
+ {
+ this->abiflags_ = new Mips_abiflags<big_endian>(*in_abiflags);
+ return;
+ }
+
+ this->abiflags_->fp_abi = this->select_fp_abi(name, in_abiflags->fp_abi,
+ this->abiflags_->fp_abi);
+
+ // Merge abiflags.
+ this->abiflags_->isa_level = std::max(this->abiflags_->isa_level,
+ in_abiflags->isa_level);
+ this->abiflags_->isa_rev = std::max(this->abiflags_->isa_rev,
+ in_abiflags->isa_rev);
+ this->abiflags_->gpr_size = std::max(this->abiflags_->gpr_size,
+ in_abiflags->gpr_size);
+ this->abiflags_->cpr1_size = std::max(this->abiflags_->cpr1_size,
+ in_abiflags->cpr1_size);
+ this->abiflags_->cpr2_size = std::max(this->abiflags_->cpr2_size,
+ in_abiflags->cpr2_size);
+ this->abiflags_->ases |= in_abiflags->ases;
+ this->abiflags_->flags1 |= in_abiflags->flags1;
+}
+
// Check whether machine EXTENSION is an extension of machine BASE.
template<int size, bool big_endian>
bool
@@ -8342,10 +8987,12 @@ Target_mips<size, big_endian>::mips_mach_extends(unsigned int base,
return false;
}
+// Merge file header flags from input object.
+
template<int size, bool big_endian>
void
-Target_mips<size, big_endian>::merge_processor_specific_flags(
- const std::string& name, elfcpp::Elf_Word in_flags, bool dyn_obj)
+Target_mips<size, big_endian>::merge_obj_e_flags(const std::string& name,
+ elfcpp::Elf_Word in_flags)
{
// If flags are not set yet, just copy them.
if (!this->are_processor_specific_flags_set())
@@ -8374,10 +9021,6 @@ Target_mips<size, big_endian>::merge_processor_specific_flags(
new_flags &= ~elfcpp::EF_MIPS_UCODE;
old_flags &= ~elfcpp::EF_MIPS_UCODE;
- // DSOs should only be linked with CPIC code.
- if (dyn_obj)
- new_flags |= elfcpp::EF_MIPS_PIC | elfcpp::EF_MIPS_CPIC;
-
if (new_flags == old_flags)
{
this->set_processor_specific_flags(merged_flags);
@@ -8413,6 +9056,9 @@ Target_mips<size, big_endian>::merge_processor_specific_flags(
merged_flags |= (new_flags & (elfcpp::EF_MIPS_ARCH
| elfcpp::EF_MIPS_MACH | elfcpp::EF_MIPS_32BITMODE));
+ // Update the ABI flags isa_level, isa_rev, isa_ext fields.
+ this->update_abiflags_isa(name, merged_flags, this->abiflags_);
+
// Copy across the ABI flags if output doesn't use them
// and if that was what caused us to treat input object as 32-bit.
if ((old_flags & elfcpp::EF_MIPS_ABI) == 0
@@ -8471,6 +9117,34 @@ Target_mips<size, big_endian>::merge_processor_specific_flags(
old_flags &= ~ elfcpp::EF_MIPS_ARCH_ASE;
}
+ // Compare NaN encodings.
+ if ((new_flags & elfcpp::EF_MIPS_NAN2008) != (old_flags & elfcpp::EF_MIPS_NAN2008))
+ {
+ gold_error(_("%s: linking %s module with previous %s modules"),
+ name.c_str(),
+ (new_flags & elfcpp::EF_MIPS_NAN2008
+ ? "-mnan=2008" : "-mnan=legacy"),
+ (old_flags & elfcpp::EF_MIPS_NAN2008
+ ? "-mnan=2008" : "-mnan=legacy"));
+
+ new_flags &= ~elfcpp::EF_MIPS_NAN2008;
+ old_flags &= ~elfcpp::EF_MIPS_NAN2008;
+ }
+
+ // Compare FP64 state.
+ if ((new_flags & elfcpp::EF_MIPS_FP64) != (old_flags & elfcpp::EF_MIPS_FP64))
+ {
+ gold_error(_("%s: linking %s module with previous %s modules"),
+ name.c_str(),
+ (new_flags & elfcpp::EF_MIPS_FP64
+ ? "-mfp64" : "-mfp32"),
+ (old_flags & elfcpp::EF_MIPS_FP64
+ ? "-mfp64" : "-mfp32"));
+
+ new_flags &= ~elfcpp::EF_MIPS_FP64;
+ old_flags &= ~elfcpp::EF_MIPS_FP64;
+ }
+
// Warn about any other mismatches.
if (new_flags != old_flags)
gold_error(_("%s: uses different e_flags (0x%x) fields than previous "
@@ -8489,13 +9163,30 @@ Target_mips<size, big_endian>::do_adjust_elf_header(
{
gold_assert(len == elfcpp::Elf_sizes<size>::ehdr_size);
- if (!this->entry_symbol_is_compressed_)
- return;
-
elfcpp::Ehdr<size, big_endian> ehdr(view);
+ unsigned char e_ident[elfcpp::EI_NIDENT];
+ elfcpp::Elf_Word flags = this->processor_specific_flags();
+ memcpy(e_ident, ehdr.get_e_ident(), elfcpp::EI_NIDENT);
+
+ unsigned char ei_abiversion = 0;
+ elfcpp::Elf_Half type = ehdr.get_e_type();
+ if (type == elfcpp::ET_EXEC
+ && parameters->options().copyreloc()
+ && (flags & (elfcpp::EF_MIPS_PIC | elfcpp::EF_MIPS_CPIC))
+ == elfcpp::EF_MIPS_CPIC)
+ ei_abiversion = 1;
+
+ if (this->abiflags_ != NULL
+ && (this->abiflags_->fp_abi == elfcpp::Val_GNU_MIPS_ABI_FP_64
+ || this->abiflags_->fp_abi == elfcpp::Val_GNU_MIPS_ABI_FP_64A))
+ ei_abiversion = 3;
+
+ e_ident[elfcpp::EI_ABIVERSION] = ei_abiversion;
elfcpp::Ehdr_write<size, big_endian> oehdr(view);
+ oehdr.put_e_ident(e_ident);
- oehdr.put_e_entry(ehdr.get_e_entry() + 1);
+ if (this->entry_symbol_is_compressed_)
+ oehdr.put_e_entry(ehdr.get_e_entry() + 1);
}
// do_make_elf_object to override the same function in the base class.
@@ -8598,7 +9289,6 @@ Target_mips<size, big_endian>::do_finalize_sections(Layout* layout,
Valtype cprmask4 = 0;
bool has_reginfo_section = false;
- // Merge processor-specific flags.
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
p != input_objects->relobj_end();
++p)
@@ -8618,49 +9308,63 @@ Target_mips<size, big_endian>::do_finalize_sections(Layout* layout,
}
Input_file::Format format = relobj->input_file()->format();
- if (format == Input_file::FORMAT_ELF)
- {
- // Read processor-specific flags in ELF file header.
- const unsigned char* pehdr = relobj->get_view(
- elfcpp::file_header_offset,
- elfcpp::Elf_sizes<size>::ehdr_size,
- true, false);
+ if (format != Input_file::FORMAT_ELF)
+ continue;
- elfcpp::Ehdr<size, big_endian> ehdr(pehdr);
- elfcpp::Elf_Word in_flags = ehdr.get_e_flags();
- // If all input sections will be discarded, don't use this object
- // file for merging processor specific flags.
- bool should_merge_processor_specific_flags = false;
+ // If all input sections will be discarded, don't use this object
+ // file for merging processor specific flags.
+ bool should_merge_processor_specific_flags = false;
- for (unsigned int i = 1; i < relobj->shnum(); ++i)
- if (relobj->output_section(i) != NULL)
- {
- should_merge_processor_specific_flags = true;
- break;
- }
+ for (unsigned int i = 1; i < relobj->shnum(); ++i)
+ if (relobj->output_section(i) != NULL)
+ {
+ should_merge_processor_specific_flags = true;
+ break;
+ }
- if (should_merge_processor_specific_flags)
- this->merge_processor_specific_flags(relobj->name(), in_flags,
- false);
- }
+ if (!should_merge_processor_specific_flags)
+ continue;
+
+ // Merge processor specific flags.
+ Mips_abiflags<big_endian> in_abiflags;
+
+ this->create_abiflags(relobj, &in_abiflags);
+ this->merge_obj_e_flags(relobj->name(),
+ relobj->processor_specific_flags());
+ this->merge_obj_abiflags(relobj->name(), &in_abiflags);
+ this->merge_obj_attributes(relobj->name(),
+ relobj->attributes_section_data());
}
- for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin();
- p != input_objects->dynobj_end();
- ++p)
+ // Create a .gnu.attributes section if we have merged any attributes
+ // from inputs.
+ if (this->attributes_section_data_ != NULL)
{
- Sized_dynobj<size, big_endian>* dynobj =
- static_cast<Sized_dynobj<size, big_endian>*>(*p);
+ Output_attributes_section_data* attributes_section =
+ new Output_attributes_section_data(*this->attributes_section_data_);
+ layout->add_output_section_data(".gnu.attributes",
+ elfcpp::SHT_GNU_ATTRIBUTES, 0,
+ attributes_section, ORDER_INVALID, false);
+ }
- // Read processor-specific flags.
- const unsigned char* pehdr = dynobj->get_view(elfcpp::file_header_offset,
- elfcpp::Elf_sizes<size>::ehdr_size,
- true, false);
+ // Create .MIPS.abiflags output section if there is an input section.
+ if (this->has_abiflags_section_)
+ {
+ Mips_output_section_abiflags<size, big_endian>* abiflags_section =
+ new Mips_output_section_abiflags<size, big_endian>(*this->abiflags_);
- elfcpp::Ehdr<size, big_endian> ehdr(pehdr);
- elfcpp::Elf_Word in_flags = ehdr.get_e_flags();
+ Output_section* os =
+ layout->add_output_section_data(".MIPS.abiflags",
+ elfcpp::SHT_MIPS_ABIFLAGS,
+ elfcpp::SHF_ALLOC,
+ abiflags_section, ORDER_INVALID, false);
- this->merge_processor_specific_flags(dynobj->name(), in_flags, true);
+ if (!parameters->options().relocatable() && os != NULL)
+ {
+ Output_segment* abiflags_segment =
+ layout->make_output_segment(elfcpp::PT_MIPS_ABIFLAGS, elfcpp::PF_R);
+ abiflags_segment->add_output_section_to_nonload(os, elfcpp::PF_R);
+ }
}
if (has_reginfo_section && !parameters->options().gc_sections())
@@ -11263,20 +11967,24 @@ Target_mips<size, big_endian>::elf_mips_mach_name(elfcpp::Elf_Word e_flags)
return "mips:5400";
case elfcpp::E_MIPS_MACH_5500:
return "mips:5500";
+ case elfcpp::E_MIPS_MACH_5900:
+ return "mips:5900";
case elfcpp::E_MIPS_MACH_SB1:
return "mips:sb1";
case elfcpp::E_MIPS_MACH_9000:
return "mips:9000";
case elfcpp::E_MIPS_MACH_LS2E:
- return "mips:loongson-2e";
+ return "mips:loongson_2e";
case elfcpp::E_MIPS_MACH_LS2F:
- return "mips:loongson-2f";
+ return "mips:loongson_2f";
case elfcpp::E_MIPS_MACH_LS3A:
- return "mips:loongson-3a";
+ return "mips:loongson_3a";
case elfcpp::E_MIPS_MACH_OCTEON:
return "mips:octeon";
case elfcpp::E_MIPS_MACH_OCTEON2:
return "mips:octeon2";
+ case elfcpp::E_MIPS_MACH_OCTEON3:
+ return "mips:octeon3";
case elfcpp::E_MIPS_MACH_XLR:
return "mips:xlr";
default: