forked from OSchip/llvm-project
				
			[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. llvm-svn: 268485
This commit is contained in:
		
							parent
							
								
									13e2c1a709
								
							
						
					
					
						commit
						add74f37f2
					
				| 
						 | 
				
			
			@ -105,7 +105,9 @@ ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getSymbols() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
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>::createInputSection(const Elf_Shdr &Sec) {
 | 
			
		|||
  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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,9 +64,10 @@ typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) {
 | 
			
		|||
  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>::MipsReginfoInputSection(elf::ObjectFile<ELFT> *F,
 | 
			
		|||
    : 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>::classof(const InputSectionBase<ELFT> *S) {
 | 
			
		|||
  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::MipsReginfoInputSection<ELF32LE>;
 | 
			
		|||
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>;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1691,6 +1691,34 @@ void MipsReginfoOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
 | 
			
		|||
  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<ELF32BE>;
 | 
			
		|||
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>;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1166,6 +1166,9 @@ OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C,
 | 
			
		|||
  case InputSectionBase<ELFT>::MipsReginfo:
 | 
			
		||||
    Sec = new MipsReginfoOutputSection<ELFT>();
 | 
			
		||||
    break;
 | 
			
		||||
  case InputSectionBase<ELFT>::MipsOptions:
 | 
			
		||||
    Sec = new MipsOptionsOutputSection<ELFT>();
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
  return {Sec, true};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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: }
 | 
			
		||||
		Loading…
	
		Reference in New Issue