Index: llvm/include/llvm/Object/ELFObjectFile.h =================================================================== --- llvm/include/llvm/Object/ELFObjectFile.h +++ llvm/include/llvm/Object/ELFObjectFile.h @@ -382,6 +382,10 @@ return Error::success(); } + virtual const Elf_Ehdr &getHeader() const { + return *EF.getHeader(); + } + // This flag is used for classof, to distinguish ELFObjectFile from // its subclass. If more subclasses will be created, this flag will // have to become an enum. @@ -421,7 +425,7 @@ Triple::ArchType getArch() const override; Expected getStartAddress() const override; - unsigned getPlatformFlags() const override { return EF.getHeader()->e_flags; } + unsigned getPlatformFlags() const override { return getHeader().e_flags; } const ELFFile *getELFFile() const { return &EF; } @@ -494,7 +498,7 @@ if (ESym->st_shndx == ELF::SHN_ABS) return Ret; - const Elf_Ehdr *Header = EF.getHeader(); + const Elf_Ehdr *Header = &getHeader(); // Clear the ARM/Thumb or microMIPS indicator flag. if ((Header->e_machine == ELF::EM_ARM || Header->e_machine == ELF::EM_MIPS) && ESym->getType() == ELF::STT_FUNC) @@ -515,7 +519,7 @@ return Result; } - const Elf_Ehdr *Header = EF.getHeader(); + const Elf_Ehdr *Header = &getHeader(); auto SymTabOrErr = EF.getSection(Symb.d.a); if (!SymTabOrErr) return SymTabOrErr.takeError(); @@ -543,11 +547,11 @@ template uint16_t ELFObjectFile::getEMachine() const { - return EF.getHeader()->e_machine; + return getHeader().e_machine; } template uint16_t ELFObjectFile::getEType() const { - return EF.getHeader()->e_type; + return getHeader().e_type; } template @@ -623,7 +627,7 @@ if (DotDynSymSecSyms && ESym == (*DotDynSymSecSyms).begin()) Result |= SymbolRef::SF_FormatSpecific; - if (EF.getHeader()->e_machine == ELF::EM_ARM) { + if (getHeader().e_machine == ELF::EM_ARM) { if (Expected NameOrErr = getSymbolName(Sym)) { StringRef Name = *NameOrErr; if (Name.startswith("$d") || Name.startswith("$t") || @@ -810,7 +814,7 @@ if (!SectionsOrErr) return relocation_iterator(RelocationRef()); uintptr_t SHT = reinterpret_cast((*SectionsOrErr).begin()); - RelData.d.a = (Sec.p - SHT) / EF.getHeader()->e_shentsize; + RelData.d.a = (Sec.p - SHT) / getHeader().e_shentsize; RelData.d.b = 0; return relocation_iterator(RelocationRef(RelData, this)); } @@ -837,7 +841,7 @@ template section_iterator ELFObjectFile::getRelocatedSection(DataRefImpl Sec) const { - if (EF.getHeader()->e_type != ELF::ET_REL) + if (getHeader().e_type != ELF::ET_REL) return section_end(); const Elf_Shdr *EShdr = getSection(Sec); @@ -896,7 +900,7 @@ template StringRef ELFObjectFile::getRelocationTypeName(uint32_t Type) const { - return getELFRelocationTypeName(EF.getHeader()->e_machine, Type); + return getELFRelocationTypeName(getHeader().e_machine, Type); } template @@ -1046,9 +1050,9 @@ template StringRef ELFObjectFile::getFileFormatName() const { bool IsLittleEndian = ELFT::TargetEndianness == support::little; - switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) { + switch (getHeader().e_ident[ELF::EI_CLASS]) { case ELF::ELFCLASS32: - switch (EF.getHeader()->e_machine) { + switch (getHeader().e_machine) { case ELF::EM_386: return "ELF32-i386"; case ELF::EM_IAMCU: @@ -1080,7 +1084,7 @@ return "ELF32-unknown"; } case ELF::ELFCLASS64: - switch (EF.getHeader()->e_machine) { + switch (getHeader().e_machine) { case ELF::EM_386: return "ELF64-i386"; case ELF::EM_X86_64: @@ -1112,7 +1116,7 @@ template Triple::ArchType ELFObjectFile::getArch() const { bool IsLittleEndian = ELFT::TargetEndianness == support::little; - switch (EF.getHeader()->e_machine) { + switch (getHeader().e_machine) { case ELF::EM_386: case ELF::EM_IAMCU: return Triple::x86; @@ -1129,7 +1133,7 @@ case ELF::EM_LANAI: return Triple::lanai; case ELF::EM_MIPS: - switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) { + switch (getHeader().e_ident[ELF::EI_CLASS]) { case ELF::ELFCLASS32: return IsLittleEndian ? Triple::mipsel : Triple::mips; case ELF::ELFCLASS64: @@ -1144,7 +1148,7 @@ case ELF::EM_PPC64: return IsLittleEndian ? Triple::ppc64le : Triple::ppc64; case ELF::EM_RISCV: - switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) { + switch (getHeader().e_ident[ELF::EI_CLASS]) { case ELF::ELFCLASS32: return Triple::riscv32; case ELF::ELFCLASS64: @@ -1165,7 +1169,7 @@ if (!IsLittleEndian) return Triple::UnknownArch; - unsigned MACH = EF.getHeader()->e_flags & ELF::EF_AMDGPU_MACH; + unsigned MACH = getHeader().e_flags & ELF::EF_AMDGPU_MACH; if (MACH >= ELF::EF_AMDGPU_MACH_R600_FIRST && MACH <= ELF::EF_AMDGPU_MACH_R600_LAST) return Triple::r600; @@ -1186,7 +1190,7 @@ template Expected ELFObjectFile::getStartAddress() const { - return EF.getHeader()->e_entry; + return getHeader().e_entry; } template @@ -1196,7 +1200,7 @@ } template bool ELFObjectFile::isRelocatableObject() const { - return EF.getHeader()->e_type == ELF::ET_REL; + return getHeader().e_type == ELF::ET_REL; } } // end namespace object Index: llvm/include/llvm/Object/MutableELFObject.h =================================================================== --- llvm/include/llvm/Object/MutableELFObject.h +++ llvm/include/llvm/Object/MutableELFObject.h @@ -90,12 +90,12 @@ struct MappingType { enum MappedType { Original, New, Removed }; - size_t Index; + uint64_t Index; MappedType Type; - MappingType(size_t Index, MappedType Type) : Index(Index), Type(Type) {} + MappingType(uint64_t Index, MappedType Type) : Index(Index), Type(Type) {} - operator size_t() const { return Index; } + operator uint64_t() const { return Index; } }; ArrayRef OriginalValues; @@ -105,7 +105,7 @@ public: explicit MutableTable(ArrayRef TheOriginalValues) : OriginalValues(TheOriginalValues) { - size_t Count = 0; + uint64_t Count = 0; std::transform(OriginalValues.begin(), OriginalValues.end(), std::back_inserter(Mappings), [&Count](const OrigType &) { return MappingType(Count++, MappingType::Original); @@ -115,7 +115,7 @@ /// Get the OrigType at index Index regardless of whether it is an OrigType /// or NewType. In the case that Mappings[Index].Type == New, call NewTypes /// operator OrigType to make the proper conversion. - const OrigType &operator[](size_t Index) const { + const OrigType &operator[](uint64_t Index) const { assert(Index < Mappings.size() && "Out of bounds"); assert(Mappings[Index].Type != MappingType::Removed); if (Mappings[Index].Type == MappingType::New) @@ -126,44 +126,41 @@ /// Get the OrigType at index Index. This method ignores any changes made /// and always returns the OrigType from its original state at its original /// index. - const OrigType &getOriginal(size_t Index) const { + const OrigType &getOriginal(uint64_t Index) const { assert(Index < OriginalValues.size() && "Out of bounds"); assert(Mappings[Index].Type != MappingType::Removed); return OriginalValues[Index]; } - /// Gets the index of the next entry that hasn't been removed after \param - /// CurrentIndex. If there is no entry after \param CurrentIndex which has - /// not been removed, this returns the index past the last entry. - size_t getNextIndex(size_t CurrentIndex) const { - assert(CurrentIndex < Mappings.size()); - return *llvm::find_if( - seq(CurrentIndex + 1, Mappings.size()), [this](size_t Index) { - return Mappings[Index].Type != MappingType::Removed; - }); + /// Gets next index that hasn't been removed after \param CurrentIndex. + uint64_t getNextIndex(uint64_t CurrentIndex) const { + auto Range = seq(CurrentIndex + 1, (uint64_t)Mappings.size()); + return *std::find_if(Range.begin(), Range.end(), [this](uint64_t Index) { + return Mappings[Index].Type != MappingType::Removed; + }); } /// Returns the first index which has not been removed. - size_t getFirstIndex() const { + uint64_t getFirstIndex() const { return Mappings[0].Type != MappingType::Removed ? 0 : getNextIndex(0); } /// Counts the number of entries that haven't been removed between 0 and /// \param Index. - size_t getEffectiveIndex(size_t Index) const { - size_t Ret = 0; - for (size_t I = 0; I < Index; ++I) + uint64_t getEffectiveIndex(uint64_t Index) const { + uint64_t Ret = 0; + for (uint64_t I = 0; I < Index; ++I) if (Mappings[I].Type != MappingType::Removed) ++Ret; return Ret; } - /// Returns the index of the last element. This is different to size() - /// because size() returns the number of entries that haven't been removed. + /// different to size() because size() returns the number of entries that + /// haven't been removed. size_t getEndIndex() const { return Mappings.size(); } /// Removes the entry at \param Index. - void remove(size_t Index) { + void remove(uint64_t Index) { assert(Index < Mappings.size() && "Out of bounds"); assert(Mappings[Index].Type != MappingType::Removed && "Entry already removed"); @@ -180,7 +177,7 @@ /// a reference to that. Otherwise, this replaces the current entry at the /// specified index with a NewType constructued with Arguments. template - NewType &makeMutable(size_t Index, Args &&... Arguments) { + NewType &makeMutable(uint64_t Index, Args &&... Arguments) { assert(Index < Mappings.size() && "Out of bounds"); assert(Mappings[Index].Type != MappingType::Removed); if (Mappings[Index].Type == MappingType::New) @@ -192,7 +189,7 @@ /// Returns a pointer to the NewType if the entry at the specified index /// has had makeMutable called on it. Otherwise this method returns nullptr. - const NewType *getConstIfNew(size_t Index) const { + const NewType *getConstIfNew(uint64_t Index) const { assert(Index < Mappings.size() && "Out of bounds"); assert(Mappings[Index].Type != MappingType::Removed); return Mappings[Index].Type == MappingType::New @@ -216,14 +213,11 @@ using MutableSymbolTable = MutableTable>; + Elf_Ehdr FileHeader; MutableTable> Sections; MutableSymbolTable Symbols; MutableSymbolTable DynSymbols; - const Elf_Ehdr &getHeader() const { - return *reinterpret_cast(this->base()); - } - /// Many getSection* methods in ELFObjectFile use getSection to get the /// the header associated with that section. This override returns a valid /// section header whether the section has been modified or not. @@ -265,6 +259,7 @@ public: explicit MutableELFObject(ELFObjectFile &&B) : ELFObjectFile(std::move(B)), + FileHeader(*reinterpret_cast(this->base())), Sections(ArrayRef(reinterpret_cast( this->base() + getHeader().e_shoff), getHeader().e_shnum)), @@ -357,15 +352,16 @@ assert(Sections.getOriginal(Sym.getRawDataRefImpl().d.a).sh_type == ELF::SHT_SYMTAB && "Not pointing to symbol table"); - assert(Sym.getRawDataRefImpl().d.b && "Cannot remove index 0 symbol"); Symbols.remove(Sym.getRawDataRefImpl().d.b); } /// Removes a section. void removeSection(SectionRef Sec) { - assert(Sec.getRawDataRefImpl().p && "Cannot remove index 0 section"); Sections.remove(Sec.getRawDataRefImpl().p); } + + const Elf_Ehdr &getHeader() const override { return FileHeader; } + Elf_Ehdr &getMutableHeader() { return FileHeader; } }; template Index: llvm/unittests/Object/MutableELFObjectTest.cpp =================================================================== --- llvm/unittests/Object/MutableELFObjectTest.cpp +++ llvm/unittests/Object/MutableELFObjectTest.cpp @@ -349,7 +349,7 @@ ASSERT_TRUE(ELFObjFile); MutableELFObject MutableObject(std::move(*ELFObjFile)); - symbol_iterator TestSym(++MutableObject.symbol_begin()); + auto TestSym = symbol_iterator(++MutableObject.symbol_begin()); Expected &> MutSymOrErr = MutableObject.getMutableSymbol(*TestSym); ASSERT_THAT_EXPECTED(MutSymOrErr, Succeeded()); @@ -387,7 +387,7 @@ ASSERT_TRUE(ELFObjFile); MutableELFObject MutableObject(std::move(*ELFObjFile)); - symbol_iterator DynSym(++MutableObject.dynamic_symbol_begin()); + auto DynSym = symbol_iterator(++MutableObject.dynamic_symbol_begin()); EXPECT_EQ(DynSym->getValue(), 0x1234U); EXPECT_TRUE(DynSym->getFlags() & SymbolRef::SF_Global); auto NameOrErr = DynSym->getName(); @@ -480,22 +480,11 @@ MutableELFObject MutableObject(std::move(*ELFObjFile)); // 4 additional sections, index 0, .symtab, .strtab and .shstrtab are added - // by yaml2obj. + // yaml2obj. EXPECT_EQ( std::distance(MutableObject.section_begin(), MutableObject.section_end()), 6); - std::vector SectionNames; - llvm::transform(MutableObject.sections(), std::back_inserter(SectionNames), - [](SectionRef Sec) { - StringRef Name; - Sec.getName(Name); - return Name; - }); - EXPECT_THAT(SectionNames, - ::testing::ElementsAre("", ".remove_me", ".remove_me_too", - ".symtab", ".strtab", ".shstrtab")); - auto Iter = ++MutableObject.section_begin(); StringRef Name; ASSERT_FALSE(Iter->getName(Name)); @@ -624,7 +613,7 @@ EXPECT_EQ( std::distance(MutableObject.symbol_begin(), MutableObject.symbol_end()), - 101); + 10001); } // Add and then remove a symbol. @@ -714,3 +703,36 @@ EXPECT_EQ(Distance(), 8); EXPECT_EQ(IterAtIndex(7)->getSize(), 100u); } + +TEST(MutableELFObject, UpdateHeader) { + SmallString<0> Storage; + Expected> ErrOrObj = yaml2ObjectFile(Storage, R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64)"); + + ASSERT_THAT_EXPECTED(ErrOrObj, Succeeded()); + auto *ELFObjFile = dyn_cast>(ErrOrObj->get()); + ASSERT_TRUE(ELFObjFile); + MutableELFObject MutableObject(std::move(*ELFObjFile)); + + Elf_Ehdr_Impl &Header = MutableObject.getMutableHeader(); + EXPECT_EQ(Header.e_type, ELF::ET_REL); + Header.e_type = ELF::ET_EXEC; + EXPECT_EQ(MutableObject.getHeader().e_type, ELF::ET_EXEC); + EXPECT_FALSE(MutableObject.isRelocatableObject()); + + Header.e_type = ELF::ET_REL; + EXPECT_TRUE(MutableObject.isRelocatableObject()); + + Header.e_flags = 100; + EXPECT_EQ(MutableObject.getPlatformFlags(), 100u); + + Header.e_entry = 5; + Expected StartAddr = MutableObject.getStartAddress(); + ASSERT_THAT_EXPECTED(StartAddr, Succeeded()); + EXPECT_EQ(*StartAddr, 5u); +}