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,17 @@ return OriginalValues[Index]; } + void remove(uint64_t Index) { + auto It = Mappings.begin(); + std::advance(It, Index); + Mappings.erase(It); + } + + void add(NewType &&New) { + NewValues.push_back(New); + Mappings.push_back(MappingType(NewValues.size() - 1, MappingType::New)); + } + template NewType &makeMutable(uint64_t Index, Args &&... Arguments) { assert(Index < Mappings.size() && "Out of bounds"); @@ -107,12 +130,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()); @@ -122,24 +151,72 @@ 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 { + 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 None; + } + + uint32_t findSymbolTableIndex(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)); @@ -149,6 +226,18 @@ return section_iterator(SectionRef(toDataRef(Sections.size()), this)); } + basic_symbol_iterator symbol_end() const override { + return basic_symbol_iterator(SymbolRef( + toDataRef(findSymbolTableIndex(ELF::SHT_SYMTAB), Symbols.size()), + this)); + } + + elf_symbol_iterator dynamic_symbol_end() const override { + return basic_symbol_iterator(SymbolRef( + toDataRef(findSymbolTableIndex(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} @@ -169,6 +258,12 @@ return Sections.makeMutable(Sec->getRawDataRefImpl().p, Header, *Name, this); } + + /// Removes either a dynamic symbol or regular symbol. + void removeSymbol(symbol_iterator Sym) { + MutableSymbolTable &SymTab = getWhichTable(Sym->getRawDataRefImpl()); + SymTab.remove(Sym->getRawDataRefImpl().d.b); + } }; template @@ -197,6 +292,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 @@ -199,3 +199,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); +}