Add Mips abiflags section to the oatfile.

Once this patch is merged, then the workaround patch:
0acb15ead6a554a6879b29fd90726b9ea8fd98c4
in bionic can be removed.

Change-Id: Ie06a3c4e384a23a77db7d04a2508edbf3a6d3933
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 943e2a8..0a474c6 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -39,6 +39,7 @@
 //   .rodata                     - DEX files and oat metadata.
 //   .text                       - Compiled code.
 //   .bss                        - Zero-initialized writeable section.
+//   .MIPS.abiflags              - MIPS specific section.
 //   .dynstr                     - Names for .dynsym.
 //   .dynsym                     - A few oat-specific dynamic symbols.
 //   .hash                       - Hash-table for .dynsym.
@@ -393,6 +394,75 @@
     }
   };
 
+  class AbiflagsSection FINAL : public Section {
+   public:
+    // Section with Mips abiflag info.
+    static constexpr uint8_t MIPS_AFL_REG_NONE =         0;  // no registers
+    static constexpr uint8_t MIPS_AFL_REG_32 =           1;  // 32-bit registers
+    static constexpr uint8_t MIPS_AFL_REG_64 =           2;  // 64-bit registers
+    static constexpr uint32_t MIPS_AFL_FLAGS1_ODDSPREG = 1;  // Uses odd single-prec fp regs
+    static constexpr uint8_t MIPS_ABI_FP_DOUBLE =        1;  // -mdouble-float
+    static constexpr uint8_t MIPS_ABI_FP_XX =            5;  // -mfpxx
+    static constexpr uint8_t MIPS_ABI_FP_64A =           7;  // -mips32r* -mfp64 -mno-odd-spreg
+
+    AbiflagsSection(ElfBuilder<ElfTypes>* owner,
+                    const std::string& name,
+                    Elf_Word type,
+                    Elf_Word flags,
+                    const Section* link,
+                    Elf_Word info,
+                    Elf_Word align,
+                    Elf_Word entsize,
+                    InstructionSet isa,
+                    const InstructionSetFeatures* features)
+        : Section(owner, name, type, flags, link, info, align, entsize) {
+      if (isa == kMips || isa == kMips64) {
+        bool fpu32 = false;    // assume mips64 values
+        uint8_t isa_rev = 6;   // assume mips64 values
+        if (isa == kMips) {
+          // adjust for mips32 values
+          fpu32 = features->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint();
+          isa_rev = features->AsMipsInstructionSetFeatures()->IsR6()
+              ? 6
+              : features->AsMipsInstructionSetFeatures()->IsMipsIsaRevGreaterThanEqual2()
+                  ? (fpu32 ? 2 : 5)
+                  : 1;
+        }
+        abiflags_.version = 0;  // version of flags structure
+        abiflags_.isa_level = (isa == kMips) ? 32 : 64;
+        abiflags_.isa_rev = isa_rev;
+        abiflags_.gpr_size = (isa == kMips) ? MIPS_AFL_REG_32 : MIPS_AFL_REG_64;
+        abiflags_.cpr1_size = fpu32 ? MIPS_AFL_REG_32 : MIPS_AFL_REG_64;
+        abiflags_.cpr2_size = MIPS_AFL_REG_NONE;
+        // Set the fp_abi to MIPS_ABI_FP_64A for mips32 with 64-bit FPUs (ie: mips32 R5 and R6).
+        // Otherwise set to MIPS_ABI_FP_DOUBLE.
+        abiflags_.fp_abi = (isa == kMips && !fpu32) ? MIPS_ABI_FP_64A : MIPS_ABI_FP_DOUBLE;
+        abiflags_.isa_ext = 0;
+        abiflags_.ases = 0;
+        // To keep the code simple, we are not using odd FP reg for single floats for both
+        // mips32 and mips64 ART. Therefore we are not setting the MIPS_AFL_FLAGS1_ODDSPREG bit.
+        abiflags_.flags1 = 0;
+        abiflags_.flags2 = 0;
+      }
+    }
+
+    Elf_Word GetSize() const {
+      return sizeof(abiflags_);
+    }
+
+    void Write() {
+      this->WriteFully(&abiflags_, sizeof(abiflags_));
+    }
+
+   private:
+    struct {
+      uint16_t version;  // version of this structure
+      uint8_t  isa_level, isa_rev, gpr_size, cpr1_size, cpr2_size;
+      uint8_t  fp_abi;
+      uint32_t isa_ext, ases, flags1, flags2;
+    } abiflags_;
+  };
+
   ElfBuilder(InstructionSet isa, const InstructionSetFeatures* features, OutputStream* output)
       : isa_(isa),
         features_(features),
@@ -412,6 +482,8 @@
         debug_info_(this, ".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0),
         debug_line_(this, ".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0),
         shstrtab_(this, ".shstrtab", 0, 1),
+        abiflags_(this, ".MIPS.abiflags", SHT_MIPS_ABIFLAGS, SHF_ALLOC, nullptr, 0, kPageSize, 0,
+                  isa, features),
         started_(false),
         write_program_headers_(false),
         loaded_size_(0u),
@@ -421,6 +493,7 @@
     dynamic_.phdr_flags_ = PF_R | PF_W;
     dynamic_.phdr_type_ = PT_DYNAMIC;
     eh_frame_hdr_.phdr_type_ = PT_GNU_EH_FRAME;
+    abiflags_.phdr_type_ = PT_MIPS_ABIFLAGS;
   }
   ~ElfBuilder() {}
 
@@ -522,7 +595,7 @@
     stream_.Flush();
 
     // The main ELF header.
-    Elf_Ehdr elf_header = MakeElfHeader(isa_);
+    Elf_Ehdr elf_header = MakeElfHeader(isa_, features_);
     elf_header.e_shoff = section_headers_offset;
     elf_header.e_shnum = shdrs.size();
     elf_header.e_shstrndx = shstrtab_.GetSectionIndex();
@@ -566,7 +639,12 @@
     Elf_Word rodata_address = rodata_.GetAddress();
     Elf_Word text_address = RoundUp(rodata_address + rodata_size, kPageSize);
     Elf_Word bss_address = RoundUp(text_address + text_size, kPageSize);
-    Elf_Word dynstr_address = RoundUp(bss_address + bss_size, kPageSize);
+    Elf_Word abiflags_address = RoundUp(bss_address + bss_size, kPageSize);
+    Elf_Word abiflags_size = 0;
+    if (isa_ == kMips || isa_ == kMips64) {
+      abiflags_size = abiflags_.GetSize();
+    }
+    Elf_Word dynstr_address = RoundUp(abiflags_address + abiflags_size, kPageSize);
 
     // Cache .dynstr, .dynsym and .hash data.
     dynstr_.Add("");  // dynstr should start with empty string.
@@ -651,6 +729,12 @@
     return loaded_size_;
   }
 
+  void WriteMIPSabiflagsSection() {
+    abiflags_.Start();
+    abiflags_.Write();
+    abiflags_.End();
+  }
+
   // Returns true if all writes and seeks on the output stream succeeded.
   bool Good() {
     return stream_.Good();
@@ -670,7 +754,7 @@
   }
 
  private:
-  static Elf_Ehdr MakeElfHeader(InstructionSet isa) {
+  static Elf_Ehdr MakeElfHeader(InstructionSet isa, const InstructionSetFeatures* features) {
     Elf_Ehdr elf_header = Elf_Ehdr();
     switch (isa) {
       case kArm:
@@ -698,18 +782,20 @@
       case kMips: {
         elf_header.e_machine = EM_MIPS;
         elf_header.e_flags = (EF_MIPS_NOREORDER |
-                               EF_MIPS_PIC       |
-                               EF_MIPS_CPIC      |
-                               EF_MIPS_ABI_O32   |
-                               EF_MIPS_ARCH_32R2);
+                              EF_MIPS_PIC       |
+                              EF_MIPS_CPIC      |
+                              EF_MIPS_ABI_O32   |
+                              features->AsMipsInstructionSetFeatures()->IsR6()
+                                  ? EF_MIPS_ARCH_32R6
+                                  : EF_MIPS_ARCH_32R2);
         break;
       }
       case kMips64: {
         elf_header.e_machine = EM_MIPS;
         elf_header.e_flags = (EF_MIPS_NOREORDER |
-                               EF_MIPS_PIC       |
-                               EF_MIPS_CPIC      |
-                               EF_MIPS_ARCH_64R6);
+                              EF_MIPS_PIC       |
+                              EF_MIPS_CPIC      |
+                              EF_MIPS_ARCH_64R6);
         break;
       }
       case kNone: {
@@ -839,6 +925,7 @@
   Section debug_info_;
   Section debug_line_;
   StringSection shstrtab_;
+  AbiflagsSection abiflags_;
   std::vector<std::unique_ptr<Section>> other_sections_;
 
   // List of used section in the order in which they were written.
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index e35662d..bed864b 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -210,6 +210,9 @@
   if (bss_size_ != 0u) {
     builder_->GetBss()->WriteNoBitsSection(bss_size_);
   }
+  if (builder_->GetIsa() == kMips || builder_->GetIsa() == kMips64) {
+    builder_->WriteMIPSabiflagsSection();
+  }
   builder_->WriteDynamicSection();
 }
 
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index b52f30e..4ca0ee5 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -147,6 +147,9 @@
       bss->WriteNoBitsSection(oat_file_->BssSize());
     }
 
+    if (isa == kMips || isa == kMips64) {
+      builder_->WriteMIPSabiflagsSection();
+    }
     builder_->PrepareDynamicSection(
         elf_file->GetPath(), rodata_size, text_size, oat_file_->BssSize());
     builder_->WriteDynamicSection();
diff --git a/runtime/elf.h b/runtime/elf.h
index d1efc92..63b18c5 100644
--- a/runtime/elf.h
+++ b/runtime/elf.h
@@ -1284,6 +1284,7 @@
 
   SHT_MIPS_REGINFO        = 0x70000006, // Register usage information
   SHT_MIPS_OPTIONS        = 0x7000000d, // General options
+  SHT_MIPS_ABIFLAGS       = 0x7000002a, // Abiflags options
 
   SHT_HIPROC        = 0x7fffffff, // Highest processor arch-specific type.
   SHT_LOUSER        = 0x80000000, // Lowest type reserved for applications.
@@ -1606,7 +1607,8 @@
   // MIPS program header types.
   PT_MIPS_REGINFO  = 0x70000000,  // Register usage information.
   PT_MIPS_RTPROC   = 0x70000001,  // Runtime procedure table.
-  PT_MIPS_OPTIONS  = 0x70000002   // Options segment.
+  PT_MIPS_OPTIONS  = 0x70000002,  // Options segment.
+  PT_MIPS_ABIFLAGS = 0x70000003   // Abiflags segment.
 };
 
 // Segment flag bits.