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()); Index: llvm/include/llvm/Object/MutableELFObject.h =================================================================== --- llvm/include/llvm/Object/MutableELFObject.h +++ llvm/include/llvm/Object/MutableELFObject.h @@ -28,7 +28,6 @@ // taking an Iterable::value_type. template class MutableRange { public: - using iterator = typename std::vector::iterator; using value_type = MappingType; @@ -215,13 +214,27 @@ iterator end() { return iterator(Sections.end(), ObjFile); } }; +template struct MutableELFSymbol { + Elf_Sym_Impl Header; + std::string Name; + + MutableELFSymbol(uintptr_t ToCopy, const MutableELFObject *ObjFile) + : Header(*ObjFile->getOriginalSymbol(toDataRef(ToCopy))) { + auto NameOrErr = ObjFile->getSymbolName(toDataRef(ToCopy)); + Name = NameOrErr ? *NameOrErr : ""; + } +}; + template class MutableELFObject : public ELFObjectFile { friend struct MutableELFSection; friend class MutableELFSegment; friend class SegmentRef; + friend struct MutableELFSymbol; MutableRange> Sections; MutableRange> Segments; + MutableRange> Symbols; + MutableRange> DynamicSymbols; protected: const Elf_Ehdr_Impl &header() { @@ -236,13 +249,33 @@ MappingType Mapping = Sections[Sec.p]; if (Mapping.IsNew) return &Sections.getNew(Mapping.Ptr)->Header; - return reinterpret_cast*>(Mapping.Ptr); + return reinterpret_cast *>(Mapping.Ptr); + } + + const Elf_Sym_Impl *getOriginalSymbol(DataRefImpl Sym) const { + return ELFObjectFile::getSymbol(Sym); + } + + const Elf_Sym_Impl *getSymbol(DataRefImpl Sym) const override { + const Elf_Shdr_Impl *Sec = + getSection(toDataRef(static_cast(Sym.d.a))); + const MutableRange> *SymbolRange = &Symbols; + if (Sec->sh_type == ELF::SHT_DYNSYM) + SymbolRange = &DynamicSymbols; + assert(Sec->sh_type == ELF::SHT_SYMTAB && "Expected symbol table"); + MappingType Mapping = SymbolRange->operator[](Sym.d.b); + if (Mapping.IsNew) + return &SymbolRange->getNew(Mapping.Ptr)->Header; + assert(Mapping.Ptr - (uintptr_t)this->base() >= Sec->sh_offset && + Mapping.Ptr - (uintptr_t)this->base() < + Sec->sh_offset + Sec->sh_size && + "Pointer not in symbol table"); + return reinterpret_cast *>(Mapping.Ptr); } const Elf_Shdr_Impl &getSectionHeader(uint64_t Index) const; const Elf_Shdr_Impl &getSectionHeader(section_iterator Sec) const; const Elf_Phdr_Impl &getSegmentHeader(uint64_t Index) const; - //Elf_Phdr_Impl &getSegmentHeader(uint64_t Index); void moveSectionNext(DataRefImpl &Sec) const override; Expected getSectionName(DataRefImpl Sec) const override; @@ -260,7 +293,6 @@ uint64_t getSegmentAlign(uint64_t Index) const; bool segmentHasSection(uint64_t Segment, uint64_t Section) const; - public: explicit MutableELFObject(ELFObjectFile &B) : ELFObjectFile(std::move(B)), @@ -279,7 +311,23 @@ reinterpret_cast(Phdrs + Index), /*IsNew=*/false); }); - }) {} + }), + Symbols([this](std::vector &Vec) { + section_iterator Iter = std::find_if( + section_begin(), section_end(), [this](section_iterator Sec) { + return getSectionHeader(Sec).sh_type == ELF::SHT_SYMTAB; + }); + if (Iter == section_end()) + return; + Elf_Shdr_Impl Header = getSectionHeader(Iter); + size_t NumSyms = Header.sh_size / sizeof(Elf_Sym_Impl); + uintptr_t Start = + Header.sh_offset + reinterpret_cast(this->base()); + for (size_t I : seq((size_t)0, NumSyms)) + Vec.emplace_back(Start + I * sizeof(Elf_Sym_Impl), + /*IsNew=*/false); + }), + DynamicSymbols([](std::vector &Vec) {}) {} section_iterator section_begin() const override { return section_iterator(SectionRef(toDataRef(0), this)); Index: llvm/unittests/Object/MutableELFObjectTest.cpp =================================================================== --- llvm/unittests/Object/MutableELFObjectTest.cpp +++ llvm/unittests/Object/MutableELFObjectTest.cpp @@ -50,7 +50,7 @@ ASSERT_TRUE(ELFObjFile); MutableELFObject MutableObject(*ELFObjFile); - auto compareSectionName = [](section_iterator Iter, const char * Name) { + auto compareSectionName = [](section_iterator Iter, const char *Name) { StringRef SecName; EXPECT_FALSE(Iter->getName(SecName)); EXPECT_EQ(SecName, Name); @@ -121,9 +121,8 @@ FirstSec = ++MutableObject.section_begin(); Contents = FirstSec->getContents(); ASSERT_THAT_EXPECTED(Contents, Succeeded()); - EXPECT_EQ(*Contents, - StringRef(reinterpret_cast(Data.data()), - Data.size())); + EXPECT_EQ(*Contents, StringRef(reinterpret_cast(Data.data()), + Data.size())); MutSec->Header.sh_size = 2; Contents = FirstSec->getContents(); @@ -377,3 +376,44 @@ EXPECT_TRUE(MutableSegment->hasSection(BssSection)); EXPECT_TRUE(SecondSegment->hasSection(BssSection)); } + +// Test symbols +TEST(MutableELFObject, NoChangeSymbol) { + 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: 0 + Binding: STB_GLOBAL)"); + + ASSERT_THAT_EXPECTED(ErrOrObj, Succeeded()); + auto *ELFObjFile = dyn_cast>(ErrOrObj->get()); + ASSERT_TRUE(ELFObjFile); + MutableELFObject MutableObject(*ELFObjFile); + + auto TestSym = symbol_iterator(MutableObject.symbol_begin()); + EXPECT_EQ(TestSym->getValue(), 0x1234U); + // STB_LOCAL means not SF_Global + 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(), 0U); + EXPECT_TRUE(SecondSym->getFlags() & SymbolRef::SF_Global); + NameOrErr = SecondSym->getName(); + ASSERT_THAT_EXPECTED(NameOrErr, Succeeded()); + EXPECT_EQ(*NameOrErr, "second"); +}