Index: lld/trunk/ELF/InputFiles.cpp =================================================================== --- lld/trunk/ELF/InputFiles.cpp +++ lld/trunk/ELF/InputFiles.cpp @@ -232,6 +232,9 @@ Sections[I] = &InputSection::Discarded; else if (Name == ".eh_frame") Sections[I] = new (this->Alloc) EHInputSection(this, &Sec); + else if (Name == ".reginfo") + Sections[I] = + new (this->Alloc) MipsReginfoInputSection(this, &Sec); else if (shouldMerge(Sec)) Sections[I] = new (this->Alloc) MergeInputSection(this, &Sec); else Index: lld/trunk/ELF/InputSection.h =================================================================== --- lld/trunk/ELF/InputSection.h +++ lld/trunk/ELF/InputSection.h @@ -35,7 +35,7 @@ ObjectFile *File; public: - enum Kind { Regular, EHFrame, Merge }; + enum Kind { Regular, EHFrame, Merge, MipsReginfo }; Kind SectionKind; InputSectionBase(ObjectFile *File, const Elf_Shdr *Header, @@ -161,6 +161,25 @@ static bool classof(const InputSectionBase *S); }; +// MIPS .reginfo section provides information on the registers used by the code +// in the object file. Linker should collect this information and write a single +// .reginfo section in the output file. The output section contains a union of +// used registers masks taken from input .reginfo sections and final value +// of the `_gp` symbol. For details: Chapter 4 / "Register Information" at +// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf +template +class MipsReginfoInputSection : public InputSectionBase { + typedef llvm::object::Elf_Mips_RegInfo Elf_Mips_RegInfo; + typedef typename llvm::object::ELFFile::Elf_Shdr Elf_Shdr; + +public: + MipsReginfoInputSection(ObjectFile *F, const Elf_Shdr *Header); + + uint32_t getGeneralMask() const; + + static bool classof(const InputSectionBase *S); +}; + } // namespace elf2 } // namespace lld Index: lld/trunk/ELF/InputSection.cpp =================================================================== --- lld/trunk/ELF/InputSection.cpp +++ lld/trunk/ELF/InputSection.cpp @@ -51,6 +51,8 @@ return cast>(this)->getOffset(Offset); case Merge: return cast>(this)->getOffset(Offset); + case MipsReginfo: + return cast>(this)->getOffset(Offset); } llvm_unreachable("Invalid section kind"); } @@ -320,6 +322,24 @@ return Base + Addend; } +template +MipsReginfoInputSection::MipsReginfoInputSection(ObjectFile *F, + const Elf_Shdr *Header) + : InputSectionBase(F, Header, InputSectionBase::MipsReginfo) {} + +template +uint32_t MipsReginfoInputSection::getGeneralMask() const { + ArrayRef D = this->getSectionData(); + if (D.size() != sizeof(Elf_Mips_RegInfo)) + error("Invalid size of .reginfo section"); + return reinterpret_cast(D.data())->ri_gprmask; +} + +template +bool MipsReginfoInputSection::classof(const InputSectionBase *S) { + return S->SectionKind == InputSectionBase::MipsReginfo; +} + namespace lld { namespace elf2 { template class InputSectionBase; @@ -341,5 +361,10 @@ template class MergeInputSection; template class MergeInputSection; template class MergeInputSection; + +template class MipsReginfoInputSection; +template class MipsReginfoInputSection; +template class MipsReginfoInputSection; +template class MipsReginfoInputSection; } } Index: lld/trunk/ELF/OutputSections.h =================================================================== --- lld/trunk/ELF/OutputSections.h +++ lld/trunk/ELF/OutputSections.h @@ -31,6 +31,7 @@ template class InputSection; template class InputSectionBase; template class MergeInputSection; +template class MipsReginfoInputSection; template class OutputSection; template class ObjectFile; template class DefinedRegular; @@ -412,6 +413,20 @@ uint32_t DtFlags1 = 0; }; +template +class MipsReginfoOutputSection final : public OutputSectionBase { + typedef llvm::object::Elf_Mips_RegInfo Elf_Mips_RegInfo; + +public: + MipsReginfoOutputSection(); + void writeTo(uint8_t *Buf) override; + + void addSection(MipsReginfoInputSection *S); + +private: + uint32_t GeneralMask = 0; +}; + // All output sections that are hadnled by the linker specially are // globally accessible. Writer initializes them, so don't use them // until Writer is initialized. Index: lld/trunk/ELF/OutputSections.cpp =================================================================== --- lld/trunk/ELF/OutputSections.cpp +++ lld/trunk/ELF/OutputSections.cpp @@ -1389,6 +1389,27 @@ return Body->isWeak() ? STB_WEAK : STB_GLOBAL; } +template +MipsReginfoOutputSection::MipsReginfoOutputSection() + : OutputSectionBase(".reginfo", SHT_MIPS_REGINFO, SHF_ALLOC) { + this->Header.sh_addralign = 4; + this->Header.sh_entsize = sizeof(Elf_Mips_RegInfo); + this->Header.sh_size = sizeof(Elf_Mips_RegInfo); +} + +template +void MipsReginfoOutputSection::writeTo(uint8_t *Buf) { + auto *R = reinterpret_cast(Buf); + R->ri_gp_value = getMipsGpAddr(); + R->ri_gprmask = GeneralMask; +} + +template +void MipsReginfoOutputSection::addSection( + MipsReginfoInputSection *S) { + GeneralMask |= S->getGeneralMask(); +} + namespace lld { namespace elf2 { template class OutputSectionBase; @@ -1446,6 +1467,11 @@ template class EHOutputSection; template class EHOutputSection; +template class MipsReginfoOutputSection; +template class MipsReginfoOutputSection; +template class MipsReginfoOutputSection; +template class MipsReginfoOutputSection; + template class MergeOutputSection; template class MergeOutputSection; template class MergeOutputSection; Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -75,6 +75,7 @@ SpecificBumpPtrAllocator> SecAlloc; SpecificBumpPtrAllocator> MSecAlloc; SpecificBumpPtrAllocator> EHSecAlloc; + SpecificBumpPtrAllocator> MReginfoSecAlloc; BumpPtrAllocator Alloc; std::vector *> OutputSections; unsigned getNumSections() const { return OutputSections.size() + 1; } @@ -618,6 +619,10 @@ Sec = new (MSecAlloc.Allocate()) MergeOutputSection(Key.Name, Key.Type, Key.Flags); break; + case InputSectionBase::MipsReginfo: + Sec = new (MReginfoSecAlloc.Allocate()) + MipsReginfoOutputSection(); + break; } OutputSections.push_back(Sec); RegularSections.push_back(Sec); @@ -635,6 +640,10 @@ static_cast *>(Sec) ->addSection(cast>(C)); break; + case InputSectionBase::MipsReginfo: + static_cast *>(Sec) + ->addSection(cast>(C)); + break; } } } Index: lld/trunk/test/ELF/basic-mips.s =================================================================== --- lld/trunk/test/ELF/basic-mips.s +++ lld/trunk/test/ELF/basic-mips.s @@ -68,7 +68,7 @@ # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 4 -# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: EntrySize: 24 # CHECK-NEXT: } # CHECK-NEXT: Section { # CHECK-NEXT: Index: 2 Index: lld/trunk/test/ELF/mips-reginfo.s =================================================================== --- lld/trunk/test/ELF/mips-reginfo.s +++ lld/trunk/test/ELF/mips-reginfo.s @@ -0,0 +1,26 @@ +# Check MIPS .reginfo section generation. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=mips-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-reginfo %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 RegInfo { +# CHECK-NEXT: GP: 0x[[GP]] +# CHECK-NEXT: General Mask: 0x10000101 +# 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: }