From 1d7df40711f91620bcc4c13ac3a73340dd67e4dd Mon Sep 17 00:00:00 2001 From: Simon Atanasyan Date: Sun, 20 Dec 2015 10:57:34 +0000 Subject: [PATCH] [ELF][MIPS] MIPS .reginfo sections handling MIPS .reginfo section provides information on the registers used by the code in the object file. Linker should collect this information and write .reginfo section in the output file. This section contains a union of used registers masks taken from input .reginfo sections and final value of the `_gp` symbol. For details see the "Register Information" section in Chapter 4 in the following document: ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf The patch implements .reginfo sections handling with a couple missed features: a) it does not put output .reginfo section into the separate REGINFO segment; b) it does not merge `ri_cprmask` masks from input section. These features will be implemented later. Differential Revision: http://reviews.llvm.org/D15669 llvm-svn: 256119 --- lld/ELF/InputFiles.cpp | 3 +++ lld/ELF/InputSection.cpp | 25 +++++++++++++++++++++++++ lld/ELF/InputSection.h | 21 ++++++++++++++++++++- lld/ELF/OutputSections.cpp | 26 ++++++++++++++++++++++++++ lld/ELF/OutputSections.h | 15 +++++++++++++++ lld/ELF/Writer.cpp | 9 +++++++++ lld/test/ELF/basic-mips.s | 2 +- lld/test/ELF/mips-reginfo.s | 26 ++++++++++++++++++++++++++ 8 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 lld/test/ELF/mips-reginfo.s diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 9af7fd878f4c..e177b9b4cec6 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -232,6 +232,9 @@ void elf2::ObjectFile::initializeSections(DenseSet &Comdats) { 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 diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 75c0bc32fe4d..71dbc6c881e5 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -51,6 +51,8 @@ InputSectionBase::getOffset(uintX_t Offset) { 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 @@ MergeInputSection::getOffset(uintX_t Offset) { 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 MergeInputSection; + +template class MipsReginfoInputSection; +template class MipsReginfoInputSection; +template class MipsReginfoInputSection; +template class MipsReginfoInputSection; } } diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index 9924bc27de13..2f955c2f687d 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -35,7 +35,7 @@ protected: 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 @@ public: 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 diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index c1501783d61e..7348f358bde7 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -1389,6 +1389,27 @@ uint8_t SymbolTableSection::getSymbolBinding(SymbolBody *Body) { 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 EHOutputSection; +template class MipsReginfoOutputSection; +template class MipsReginfoOutputSection; +template class MipsReginfoOutputSection; +template class MipsReginfoOutputSection; + template class MergeOutputSection; template class MergeOutputSection; template class MergeOutputSection; diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 0626b9ddea0e..d01eb7355aed 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -31,6 +31,7 @@ template class EHInputSection; 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 @@ private: 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. diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 6427b8b3f896..b5fa2b94741e 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -75,6 +75,7 @@ private: SpecificBumpPtrAllocator> SecAlloc; SpecificBumpPtrAllocator> MSecAlloc; SpecificBumpPtrAllocator> EHSecAlloc; + SpecificBumpPtrAllocator> MReginfoSecAlloc; BumpPtrAllocator Alloc; std::vector *> OutputSections; unsigned getNumSections() const { return OutputSections.size() + 1; } @@ -618,6 +619,10 @@ template void Writer::createSections() { 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 @@ template void Writer::createSections() { static_cast *>(Sec) ->addSection(cast>(C)); break; + case InputSectionBase::MipsReginfo: + static_cast *>(Sec) + ->addSection(cast>(C)); + break; } } } diff --git a/lld/test/ELF/basic-mips.s b/lld/test/ELF/basic-mips.s index e07d2d2af8c8..0c8733f8c9c4 100644 --- a/lld/test/ELF/basic-mips.s +++ b/lld/test/ELF/basic-mips.s @@ -68,7 +68,7 @@ __start: # 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 diff --git a/lld/test/ELF/mips-reginfo.s b/lld/test/ELF/mips-reginfo.s new file mode 100644 index 000000000000..dd4771c98b8d --- /dev/null +++ b/lld/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: }