Index: llvm/include/llvm/Object/ELFObjectFile.h =================================================================== --- llvm/include/llvm/Object/ELFObjectFile.h +++ llvm/include/llvm/Object/ELFObjectFile.h @@ -394,7 +394,7 @@ const Elf_Rel *getRel(DataRefImpl Rel) const; const Elf_Rela *getRela(DataRefImpl Rela) const; - const Elf_Sym *getSymbol(DataRefImpl Sym) const { + virtual const Elf_Sym *getSymbol(DataRefImpl Sym) const { auto Ret = EF.template getEntry(Sym.d.a, Sym.d.b); if (!Ret) report_fatal_error(errorToErrorCode(Ret.takeError()).message()); @@ -409,7 +409,7 @@ basic_symbol_iterator symbol_end() const override; elf_symbol_iterator dynamic_symbol_begin() const; - elf_symbol_iterator dynamic_symbol_end() const; + virtual elf_symbol_iterator dynamic_symbol_end() const; section_iterator section_begin() const override; section_iterator section_end() const override; Index: llvm/include/llvm/Object/MutableELFObject.h =================================================================== --- llvm/include/llvm/Object/MutableELFObject.h +++ llvm/include/llvm/Object/MutableELFObject.h @@ -40,6 +40,18 @@ operator const Elf_Shdr &() const { return Header; } }; +template struct MutableELFSymbol { + using Elf_Sym = Elf_Sym_Impl; + + Elf_Sym Header; + std::string Name; + + MutableELFSymbol(const Elf_Sym &Header, StringRef Name) + : Header(Header), Name(Name) {} + + operator const Elf_Sym &() const { return Header; } +}; + template class MutableELFObject : public ELFObjectFile { // NewType must have a conversion operator to OrigType. template class MutableTable { @@ -80,6 +92,16 @@ return OriginalValues[Index]; } + void remove(uint64_t Index) { + assert(Index < OriginalValues.size() && "Out of bounds"); + Mappings.erase(Mappings.begin() + Index); + } + + void add(NewType &&New) { + NewValues.push_back(New); + Mappings.emplace_back(NewValues.size() - 1, MappingType::New); + } + template NewType &makeMutable(uint64_t Index, Args &&... Arguments) { assert(Index < Mappings.size() && "Out of bounds"); @@ -100,12 +122,18 @@ } size_t size() const { return Mappings.size(); } + size_t originalSize() const { return OriginalValues.size(); } }; using Elf_Shdr = Elf_Shdr_Impl; using Elf_Ehdr = Elf_Ehdr_Impl; + using Elf_Sym = Elf_Sym_Impl; + + using MutableSymbolTable = MutableTable>; MutableTable> Sections; + MutableSymbolTable Symbols; + MutableSymbolTable DynSymbols; const Elf_Ehdr &getHeader() const { return *reinterpret_cast(this->base()); @@ -115,24 +143,74 @@ return &Sections[Sec.p]; } + const Elf_Sym *getSymbol(DataRefImpl Sym) const override { + if (Sections.getOriginal(Sym.d.a).sh_type == ELF::SHT_SYMTAB) + return &Symbols[Sym.d.b]; + assert(Sections.getOriginal(Sym.d.a).sh_type == ELF::SHT_DYNSYM); + return &DynSymbols[Sym.d.b]; + } + void moveSectionNext(DataRefImpl &Sec) const override; Expected getSectionName(DataRefImpl Sec) const override; uint64_t getSectionIndex(DataRefImpl Sec) const override; Expected> getSectionContents(DataRefImpl Sec) const override; + Expected getSymbolName(DataRefImpl Sym) const override; + + ArrayRef findSymbolTable(uint64_t ShType) const { + assert(ShType == ELF::SHT_SYMTAB || + ShType == ELF::SHT_DYNSYM && "Not a symbol table type"); + for (const auto &Sec : this->sections()) + if (ELFSectionRef(Sec).getType() == ShType) + return ArrayRef( + reinterpret_cast(this->base() + + ELFSectionRef(Sec).getOffset()), + Sec.getSize() / sizeof(Elf_Sym)); + + return {}; + } + + uint32_t findSectionIndex(uint64_t ShType) const { + for (uint32_t I = 0; I < Sections.originalSize(); ++I) + if (Sections.getOriginal(I).sh_type == ShType) + return I; + return 0; + } + + const MutableSymbolTable &getWhichTable(DataRefImpl Sym) const { + return Sections.getOriginal(Sym.d.a).sh_type == ELF::SHT_SYMTAB + ? Symbols + : DynSymbols; + } + + MutableSymbolTable &getWhichTable(DataRefImpl Sym) { + return Sections.getOriginal(Sym.d.a).sh_type == ELF::SHT_SYMTAB + ? Symbols + : DynSymbols; + } + static DataRefImpl toDataRef(uintptr_t Ptr) { DataRefImpl Ref; Ref.p = Ptr; return Ref; } + static inline DataRefImpl toDataRef(uint32_t A, uint32_t B) { + DataRefImpl Ref; + Ref.d.a = A; + Ref.d.b = B; + return Ref; + } + public: explicit MutableELFObject(ELFObjectFile &&B) : ELFObjectFile(std::move(B)), Sections(ArrayRef(reinterpret_cast( this->base() + getHeader().e_shoff), - getHeader().e_shnum)) {} + getHeader().e_shnum)), + Symbols(findSymbolTable(ELF::SHT_SYMTAB)), + DynSymbols(findSymbolTable(ELF::SHT_DYNSYM)) {} section_iterator section_begin() const override { return section_iterator(SectionRef(toDataRef(0), this)); @@ -142,6 +220,16 @@ return section_iterator(SectionRef(toDataRef(Sections.size()), this)); } + basic_symbol_iterator symbol_end() const override { + return basic_symbol_iterator(SymbolRef( + toDataRef(findSectionIndex(ELF::SHT_SYMTAB), Symbols.size()), this)); + } + + elf_symbol_iterator dynamic_symbol_end() const override { + return basic_symbol_iterator(SymbolRef( + toDataRef(findSectionIndex(ELF::SHT_DYNSYM), Symbols.size()), this)); + } + /// Returns a mutable reference to the section pointed to by Sec. A possible /// usage to change all sections with alignment of 0 to 1 could be: /// @code{.cpp} @@ -167,6 +255,28 @@ Expected &> getMutableSection(section_iterator Sec) { return getMutableSection(*Sec); } + + /// Removes a symbol. + void removeSymbol(SymbolRef Sym) { + assert(Sections.getOriginal(Sym.getRawDataRefImpl().d.a).sh_type == + ELF::SHT_SYMTAB && + "Not pointing to symbol table"); + Symbols.remove(Sym.getRawDataRefImpl().d.b); + } + + /// Removes a symbol. + void removeSymbol(symbol_iterator Sym) { removeSymbol(*Sym); } + + /// Removes a dynamic symbol. + void removeDynamicSymbol(SymbolRef Sym) { + assert(Sections.getOriginal(Sym.getRawDataRefImpl().d.a).sh_type == + ELF::SHT_DYNSYM && + "Not pointing to dynamic symbol table"); + DynSymbols.remove(Sym.getRawDataRefImpl().d.b); + } + + /// Removes a dynamic symbol. + void removeDynamicSymbol(symbol_iterator Sym) { removeDynamicSymbol(*Sym); } }; template @@ -195,6 +305,16 @@ return ELFObjectFile::getSectionContents(Sec); } +template +Expected +MutableELFObject::getSymbolName(DataRefImpl Sym) const { + const MutableSymbolTable &SymbolTable = getWhichTable(Sym); + if (const MutableELFSymbol *SymOrNull = + SymbolTable.getConstIfNew(Sym.d.b)) + return SymOrNull->Name; + return ELFObjectFile::getSymbolName(Sym); +} + } // namespace object } // namespace llvm Index: llvm/unittests/Object/MutableELFObjectTest.cpp =================================================================== --- llvm/unittests/Object/MutableELFObjectTest.cpp +++ llvm/unittests/Object/MutableELFObjectTest.cpp @@ -214,3 +214,111 @@ std::distance(MutableObject.section_begin(), MutableObject.section_end()); EXPECT_EQ(NewNumSections, NumSections); } + +// Test basic public methods on symbols. +TEST(MutableELFObject, BasicSymbol) { + SmallString<0> Storage; + Expected> ErrOrObj = yaml2ObjectFile(Storage, R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Symbols: + - Name: test + Index: SHN_ABS + Value: 0x1234 + Binding: STB_LOCAL + - Name: second + Index: SHN_ABS + Value: 1 + Binding: STB_GLOBAL)"); + + ASSERT_THAT_EXPECTED(ErrOrObj, Succeeded()); + auto *ELFObjFile = dyn_cast>(ErrOrObj->get()); + ASSERT_TRUE(ELFObjFile); + MutableELFObject MutableObject(std::move(*ELFObjFile)); + + auto TestSym = symbol_iterator(MutableObject.symbol_begin()); + EXPECT_EQ(TestSym->getValue(), 0x1234U); + EXPECT_FALSE(TestSym->getFlags() & SymbolRef::SF_Global); + auto NameOrErr = TestSym->getName(); + ASSERT_THAT_EXPECTED(NameOrErr, Succeeded()); + EXPECT_EQ(*NameOrErr, "test"); + + auto SecondSym = symbol_iterator(++TestSym); + EXPECT_EQ(SecondSym->getValue(), 1U); + EXPECT_TRUE(SecondSym->getFlags() & SymbolRef::SF_Global); + NameOrErr = SecondSym->getName(); + ASSERT_THAT_EXPECTED(NameOrErr, Succeeded()); + EXPECT_EQ(*NameOrErr, "second"); +} + +// Test basic public methods on dynamic symbols. +TEST(MutableELFObject, BasicDynSymb) { + SmallString<0> Storage; + Expected> ErrOrObj = yaml2ObjectFile(Storage, R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +DynamicSymbols: + - Name: test + Index: SHN_ABS + Value: 0x1234 + Binding: STB_GLOBAL)"); + + ASSERT_THAT_EXPECTED(ErrOrObj, Succeeded()); + auto *ELFObjFile = dyn_cast>(ErrOrObj->get()); + ASSERT_TRUE(ELFObjFile); + MutableELFObject MutableObject(std::move(*ELFObjFile)); + + auto DynSym = symbol_iterator(++MutableObject.dynamic_symbol_begin()); + EXPECT_EQ(DynSym->getValue(), 0x1234U); + EXPECT_TRUE(DynSym->getFlags() & SymbolRef::SF_Global); + auto NameOrErr = DynSym->getName(); + ASSERT_THAT_EXPECTED(NameOrErr, Succeeded()); + EXPECT_EQ(*NameOrErr, "test"); +} + +TEST(MutableELFObject, RemoveSymbols) { + SmallString<0> Storage; + Expected> ErrOrObj = yaml2ObjectFile(Storage, R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Symbols: + - Name: first + Index: SHN_ABS + Value: 0x1234 + Binding: STB_LOCAL + - Name: second + Index: SHN_ABS + Value: 0 + Binding: STB_GLOBAL)"); + + ASSERT_THAT_EXPECTED(ErrOrObj, Succeeded()); + auto *ELFObjFile = dyn_cast>(ErrOrObj->get()); + ASSERT_TRUE(ELFObjFile); + MutableELFObject MutableObject(std::move(*ELFObjFile)); + + auto Distance = + std::distance(MutableObject.symbol_begin(), MutableObject.symbol_end()); + EXPECT_EQ(Distance, 2); + + auto FirstSym = MutableObject.symbol_begin(); + auto NameOrErr = symbol_iterator(FirstSym)->getName(); + ASSERT_THAT_EXPECTED(NameOrErr, Succeeded()); + EXPECT_EQ(*NameOrErr, "first"); + MutableObject.removeSymbol(FirstSym); + + Distance = + std::distance(MutableObject.symbol_begin(), MutableObject.symbol_end()); + EXPECT_EQ(Distance, 1); +}