[lld] r268485 - [ELF][MIPS] Read/write .MIPS.options section

Simon Atanasyan via llvm-commits llvm-commits at lists.llvm.org
Wed May 4 03:07:39 PDT 2016


Author: atanasyan
Date: Wed May  4 05:07:38 2016
New Revision: 268485

URL: http://llvm.org/viewvc/llvm-project?rev=268485&view=rev
Log:
[ELF][MIPS] Read/write .MIPS.options section

MIPS N64 ABI introduces .MIPS.options section which specifies miscellaneous
options to be applied to an object/shared/executable file. LLVM as well as
modern versions of GNU tools read and write the only type of the options -
ODK_REGINFO. It is exact copy of .reginfo section used by O32 ABI.

Added:
    lld/trunk/test/ELF/mips-options.s
Modified:
    lld/trunk/ELF/InputFiles.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/InputSection.h
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=268485&r1=268484&r2=268485&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Wed May  4 05:07:38 2016
@@ -105,7 +105,9 @@ ArrayRef<SymbolBody *> elf::ObjectFile<E
 }
 
 template <class ELFT> uint32_t elf::ObjectFile<ELFT>::getMipsGp0() const {
-  if (MipsReginfo)
+  if (ELFT::Is64Bits && MipsOptions && MipsOptions->Reginfo)
+    return MipsOptions->Reginfo->ri_gp_value;
+  if (!ELFT::Is64Bits && MipsReginfo && MipsReginfo->Reginfo)
     return MipsReginfo->Reginfo->ri_gp_value;
   return 0;
 }
@@ -278,11 +280,17 @@ elf::ObjectFile<ELFT>::createInputSectio
   if (Config->StripDebug && Name.startswith(".debug"))
     return &InputSection<ELFT>::Discarded;
 
-  // A MIPS object file has a special section that contains register
-  // usage info, which needs to be handled by the linker specially.
-  if (Config->EMachine == EM_MIPS && Name == ".reginfo") {
-    MipsReginfo.reset(new MipsReginfoInputSection<ELFT>(this, &Sec));
-    return MipsReginfo.get();
+  // A MIPS object file has a special sections that contain register
+  // usage info, which need to be handled by the linker specially.
+  if (Config->EMachine == EM_MIPS) {
+    if (Name == ".reginfo") {
+      MipsReginfo.reset(new MipsReginfoInputSection<ELFT>(this, &Sec));
+      return MipsReginfo.get();
+    }
+    if (Name == ".MIPS.options") {
+      MipsOptions.reset(new MipsOptionsInputSection<ELFT>(this, &Sec));
+      return MipsOptions.get();
+    }
   }
 
   // We dont need special handling of .eh_frame sections if relocatable

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=268485&r1=268484&r2=268485&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Wed May  4 05:07:38 2016
@@ -162,6 +162,8 @@ private:
 
   // MIPS .reginfo section defined by this file.
   std::unique_ptr<MipsReginfoInputSection<ELFT>> MipsReginfo;
+  // MIPS .MIPS.options section defined by this file.
+  std::unique_ptr<MipsOptionsInputSection<ELFT>> MipsOptions;
 
   llvm::BumpPtrAllocator Alloc;
   llvm::SpecificBumpPtrAllocator<InputSection<ELFT>> IAlloc;

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=268485&r1=268484&r2=268485&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Wed May  4 05:07:38 2016
@@ -64,9 +64,10 @@ typename ELFT::uint InputSectionBase<ELF
   case Merge:
     return cast<MergeInputSection<ELFT>>(this)->getOffset(Offset);
   case MipsReginfo:
-    // MIPS .reginfo sections are consumed by the linker,
+  case MipsOptions:
+    // MIPS .reginfo and .MIPS.options sections are consumed by the linker,
     // so it should never be copied to output.
-    llvm_unreachable("MIPS .reginfo reached writeTo().");
+    llvm_unreachable("MIPS reginfo/options section reached writeTo().");
   }
   llvm_unreachable("invalid section kind");
 }
@@ -493,8 +494,10 @@ MipsReginfoInputSection<ELFT>::MipsRegin
     : InputSectionBase<ELFT>(F, Hdr, InputSectionBase<ELFT>::MipsReginfo) {
   // Initialize this->Reginfo.
   ArrayRef<uint8_t> D = this->getSectionData();
-  if (D.size() != sizeof(Elf_Mips_RegInfo<ELFT>))
-    fatal("invalid size of .reginfo section");
+  if (D.size() != sizeof(Elf_Mips_RegInfo<ELFT>)) {
+    error("invalid size of .reginfo section");
+    return;
+  }
   Reginfo = reinterpret_cast<const Elf_Mips_RegInfo<ELFT> *>(D.data());
 }
 
@@ -503,6 +506,31 @@ bool MipsReginfoInputSection<ELFT>::clas
   return S->SectionKind == InputSectionBase<ELFT>::MipsReginfo;
 }
 
+template <class ELFT>
+MipsOptionsInputSection<ELFT>::MipsOptionsInputSection(elf::ObjectFile<ELFT> *F,
+                                                       const Elf_Shdr *Hdr)
+    : InputSectionBase<ELFT>(F, Hdr, InputSectionBase<ELFT>::MipsOptions) {
+  // Find ODK_REGINFO option in the section's content.
+  ArrayRef<uint8_t> D = this->getSectionData();
+  while (!D.empty()) {
+    if (D.size() < sizeof(Elf_Mips_Options<ELFT>)) {
+      error("invalid size of .MIPS.options section");
+      break;
+    }
+    auto *O = reinterpret_cast<const Elf_Mips_Options<ELFT> *>(D.data());
+    if (O->kind == ODK_REGINFO) {
+      Reginfo = &O->getRegInfo();
+      break;
+    }
+    D = D.slice(O->size);
+  }
+}
+
+template <class ELFT>
+bool MipsOptionsInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
+  return S->SectionKind == InputSectionBase<ELFT>::MipsOptions;
+}
+
 template class elf::InputSectionBase<ELF32LE>;
 template class elf::InputSectionBase<ELF32BE>;
 template class elf::InputSectionBase<ELF64LE>;
@@ -532,3 +560,8 @@ template class elf::MipsReginfoInputSect
 template class elf::MipsReginfoInputSection<ELF32BE>;
 template class elf::MipsReginfoInputSection<ELF64LE>;
 template class elf::MipsReginfoInputSection<ELF64BE>;
+
+template class elf::MipsOptionsInputSection<ELF32LE>;
+template class elf::MipsOptionsInputSection<ELF32BE>;
+template class elf::MipsOptionsInputSection<ELF64LE>;
+template class elf::MipsOptionsInputSection<ELF64BE>;

Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=268485&r1=268484&r2=268485&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Wed May  4 05:07:38 2016
@@ -88,7 +88,7 @@ protected:
   ObjectFile<ELFT> *File;
 
 public:
-  enum Kind { Regular, EHFrame, Merge, MipsReginfo };
+  enum Kind { Regular, EHFrame, Merge, MipsReginfo, MipsOptions };
   Kind SectionKind;
 
   InputSectionBase() : Repl(this) {}
@@ -249,7 +249,18 @@ public:
   MipsReginfoInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Hdr);
   static bool classof(const InputSectionBase<ELFT> *S);
 
-  const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo;
+  const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo = nullptr;
+};
+
+template <class ELFT>
+class MipsOptionsInputSection : public InputSectionBase<ELFT> {
+  typedef typename ELFT::Shdr Elf_Shdr;
+
+public:
+  MipsOptionsInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Hdr);
+  static bool classof(const InputSectionBase<ELFT> *S);
+
+  const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo = nullptr;
 };
 
 } // namespace elf

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=268485&r1=268484&r2=268485&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Wed May  4 05:07:38 2016
@@ -1691,6 +1691,34 @@ void MipsReginfoOutputSection<ELFT>::add
   GprMask |= S->Reginfo->ri_gprmask;
 }
 
+template <class ELFT>
+MipsOptionsOutputSection<ELFT>::MipsOptionsOutputSection()
+    : OutputSectionBase<ELFT>(".MIPS.options", SHT_MIPS_OPTIONS,
+                              SHF_ALLOC | SHF_MIPS_NOSTRIP) {
+  this->Header.sh_addralign = 8;
+  this->Header.sh_entsize = 1;
+  this->Header.sh_size = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
+}
+
+template <class ELFT>
+void MipsOptionsOutputSection<ELFT>::writeTo(uint8_t *Buf) {
+  auto *Opt = reinterpret_cast<Elf_Mips_Options *>(Buf);
+  Opt->kind = ODK_REGINFO;
+  Opt->size = this->Header.sh_size;
+  Opt->section = 0;
+  Opt->info = 0;
+  auto *Reg = reinterpret_cast<Elf_Mips_RegInfo *>(Buf + sizeof(*Opt));
+  Reg->ri_gp_value = Out<ELFT>::Got->getVA() + MipsGPOffset;
+  Reg->ri_gprmask = GprMask;
+}
+
+template <class ELFT>
+void MipsOptionsOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
+  auto *S = cast<MipsOptionsInputSection<ELFT>>(C);
+  if (S->Reginfo)
+    GprMask |= S->Reginfo->ri_gprmask;
+}
+
 namespace lld {
 namespace elf {
 template class OutputSectionBase<ELF32LE>;
@@ -1758,6 +1786,11 @@ template class MipsReginfoOutputSection<
 template class MipsReginfoOutputSection<ELF64LE>;
 template class MipsReginfoOutputSection<ELF64BE>;
 
+template class MipsOptionsOutputSection<ELF32LE>;
+template class MipsOptionsOutputSection<ELF32BE>;
+template class MipsOptionsOutputSection<ELF64LE>;
+template class MipsOptionsOutputSection<ELF64BE>;
+
 template class MergeOutputSection<ELF32LE>;
 template class MergeOutputSection<ELF32BE>;
 template class MergeOutputSection<ELF64LE>;

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=268485&r1=268484&r2=268485&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Wed May  4 05:07:38 2016
@@ -501,6 +501,20 @@ private:
   uint32_t GprMask = 0;
 };
 
+template <class ELFT>
+class MipsOptionsOutputSection final : public OutputSectionBase<ELFT> {
+  typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
+  typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
+
+public:
+  MipsOptionsOutputSection();
+  void writeTo(uint8_t *Buf) override;
+  void addSection(InputSectionBase<ELFT> *S) override;
+
+private:
+  uint32_t GprMask = 0;
+};
+
 // --eh-frame-hdr option tells linker to construct a header for all the
 // .eh_frame sections. This header is placed to a section named .eh_frame_hdr
 // and also to a PT_GNU_EH_FRAME segment.

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=268485&r1=268484&r2=268485&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Wed May  4 05:07:38 2016
@@ -1166,6 +1166,9 @@ OutputSectionFactory<ELFT>::create(Input
   case InputSectionBase<ELFT>::MipsReginfo:
     Sec = new MipsReginfoOutputSection<ELFT>();
     break;
+  case InputSectionBase<ELFT>::MipsOptions:
+    Sec = new MipsOptionsOutputSection<ELFT>();
+    break;
   }
   return {Sec, true};
 }

Added: lld/trunk/test/ELF/mips-options.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-options.s?rev=268485&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-options.s (added)
+++ lld/trunk/test/ELF/mips-options.s Wed May  4 05:07:38 2016
@@ -0,0 +1,28 @@
+# Check MIPS .MIPS.options section generation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -shared -o %t.so
+# RUN: llvm-readobj -symbols -mips-options %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+    lw   $t0,%call16(g1)($gp)
+
+# CHECK:      Name: _gp
+# CHECK-NEXT: Value: 0x[[GP:[0-9A-F]+]]
+
+# CHECK:      MIPS Options {
+# CHECK-NEXT:   ODK_REGINFO {
+# CHECK-NEXT:     GP: 0x[[GP]]
+# CHECK-NEXT:     General Mask: 0x10001001
+# CHECK-NEXT:     Co-Proc Mask0: 0x0
+# CHECK-NEXT:     Co-Proc Mask1: 0x0
+# CHECK-NEXT:     Co-Proc Mask2: 0x0
+# CHECK-NEXT:     Co-Proc Mask3: 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: }




More information about the llvm-commits mailing list