[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:
Simon Atanasyan 2016-05-04 10:07:38 +00:00
parent 13e2c1a709
commit add74f37f2
8 changed files with 144 additions and 12 deletions

View File

@ -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

View File

@ -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;

View File

@ -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>;

View File

@ -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

View File

@ -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>;

View File

@ -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.

View File

@ -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};
}

View File

@ -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: }