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