diff options
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 112 | ||||
| -rw-r--r-- | llvm/lib/ObjCopy/ELF/ELFObject.cpp | 41 | ||||
| -rw-r--r-- | llvm/lib/ObjCopy/ELF/ELFObject.h | 7 |
3 files changed, 144 insertions, 16 deletions
diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index 4793651..42581af 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -609,6 +609,112 @@ static void addSymbol(Object &Obj, const NewSymbolInfo &SymInfo, Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0); } +namespace { +struct RemoveNoteDetail { + struct DeletedRange { + uint64_t OldFrom; + uint64_t OldTo; + }; + + template <class ELFT> + static std::vector<DeletedRange> + findNotesToRemove(ArrayRef<uint8_t> Data, size_t Align, + ArrayRef<RemoveNoteInfo> NotesToRemove); + static std::vector<uint8_t> updateData(ArrayRef<uint8_t> OldData, + ArrayRef<DeletedRange> ToRemove); +}; +} // namespace + +template <class ELFT> +std::vector<RemoveNoteDetail::DeletedRange> +RemoveNoteDetail::findNotesToRemove(ArrayRef<uint8_t> Data, size_t Align, + ArrayRef<RemoveNoteInfo> NotesToRemove) { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT); + std::vector<DeletedRange> ToRemove; + uint64_t CurPos = 0; + while (CurPos + sizeof(Elf_Nhdr) <= Data.size()) { + auto Nhdr = reinterpret_cast<const Elf_Nhdr *>(Data.data() + CurPos); + size_t FullSize = Nhdr->getSize(Align); + if (CurPos + FullSize > Data.size()) + break; + Elf_Note Note(*Nhdr); + bool ShouldRemove = + llvm::any_of(NotesToRemove, [&Note](const RemoveNoteInfo &NoteInfo) { + return NoteInfo.TypeId == Note.getType() && + (NoteInfo.Name.empty() || NoteInfo.Name == Note.getName()); + }); + if (ShouldRemove) + ToRemove.push_back({CurPos, CurPos + FullSize}); + CurPos += FullSize; + } + return ToRemove; +} + +std::vector<uint8_t> +RemoveNoteDetail::updateData(ArrayRef<uint8_t> OldData, + ArrayRef<DeletedRange> ToRemove) { + std::vector<uint8_t> NewData; + NewData.reserve(OldData.size()); + uint64_t CurPos = 0; + for (const DeletedRange &RemRange : ToRemove) { + if (CurPos < RemRange.OldFrom) { + auto Slice = OldData.slice(CurPos, RemRange.OldFrom - CurPos); + NewData.insert(NewData.end(), Slice.begin(), Slice.end()); + } + CurPos = RemRange.OldTo; + } + if (CurPos < OldData.size()) { + auto Slice = OldData.slice(CurPos); + NewData.insert(NewData.end(), Slice.begin(), Slice.end()); + } + return NewData; +} + +static Error removeNotes(Object &Obj, endianness Endianness, + ArrayRef<RemoveNoteInfo> NotesToRemove, + function_ref<Error(Error)> ErrorCallback) { + // TODO: Support note segments. + if (ErrorCallback) { + for (Segment &Seg : Obj.segments()) { + if (Seg.Type == PT_NOTE) { + if (Error E = ErrorCallback(createStringError( + errc::not_supported, "note segments are not supported"))) + return E; + break; + } + } + } + for (auto &Sec : Obj.sections()) { + if (Sec.Type != SHT_NOTE || !Sec.hasContents()) + continue; + // TODO: Support note sections in segments. + if (Sec.ParentSegment) { + if (ErrorCallback) + if (Error E = ErrorCallback(createStringError( + errc::not_supported, + "cannot remove note(s) from " + Sec.Name + + ": sections in segments are not supported"))) + return E; + continue; + } + ArrayRef<uint8_t> OldData = Sec.getContents(); + size_t Align = std::max<size_t>(4, Sec.Align); + // Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the + // header, so the parsers are the same. + auto ToRemove = (Endianness == endianness::little) + ? RemoveNoteDetail::findNotesToRemove<ELF64LE>( + OldData, Align, NotesToRemove) + : RemoveNoteDetail::findNotesToRemove<ELF64BE>( + OldData, Align, NotesToRemove); + if (!ToRemove.empty()) { + if (Error E = Obj.updateSectionData( + Sec, RemoveNoteDetail::updateData(OldData, ToRemove))) + return E; + } + } + return Error::success(); +} + static Error handleUserSection(const NewSectionInfo &NewSection, function_ref<Error(StringRef, ArrayRef<uint8_t>)> F) { @@ -799,6 +905,12 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig, ? endianness::little : endianness::big; + if (!ELFConfig.NotesToRemove.empty()) { + if (Error Err = + removeNotes(Obj, E, ELFConfig.NotesToRemove, Config.ErrorCallback)) + return Err; + } + for (const NewSectionInfo &AddedSection : Config.AddSection) { auto AddSection = [&](StringRef Name, ArrayRef<uint8_t> Data) -> Error { OwnedDataSection &NewSection = diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp index 01c2f24..45c7ea4 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp @@ -2154,37 +2154,46 @@ ELFWriter<ELFT>::ELFWriter(Object &Obj, raw_ostream &Buf, bool WSH, : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs), OnlyKeepDebug(OnlyKeepDebug) {} -Error Object::updateSection(StringRef Name, ArrayRef<uint8_t> Data) { - auto It = llvm::find_if(Sections, - [&](const SecPtr &Sec) { return Sec->Name == Name; }); - if (It == Sections.end()) - return createStringError(errc::invalid_argument, "section '%s' not found", - Name.str().c_str()); - - auto *OldSec = It->get(); - if (!OldSec->hasContents()) +Error Object::updateSectionData(SecPtr &Sec, ArrayRef<uint8_t> Data) { + if (!Sec->hasContents()) return createStringError( errc::invalid_argument, "section '%s' cannot be updated because it does not have contents", - Name.str().c_str()); + Sec->Name.c_str()); - if (Data.size() > OldSec->Size && OldSec->ParentSegment) + if (Data.size() > Sec->Size && Sec->ParentSegment) return createStringError(errc::invalid_argument, "cannot fit data of size %zu into section '%s' " "with size %" PRIu64 " that is part of a segment", - Data.size(), Name.str().c_str(), OldSec->Size); + Data.size(), Sec->Name.c_str(), Sec->Size); - if (!OldSec->ParentSegment) { - *It = std::make_unique<OwnedDataSection>(*OldSec, Data); + if (!Sec->ParentSegment) { + Sec = std::make_unique<OwnedDataSection>(*Sec, Data); } else { // The segment writer will be in charge of updating these contents. - OldSec->Size = Data.size(); - UpdatedSections[OldSec] = Data; + Sec->Size = Data.size(); + UpdatedSections[Sec.get()] = Data; } return Error::success(); } +Error Object::updateSection(StringRef Name, ArrayRef<uint8_t> Data) { + auto It = llvm::find_if(Sections, + [&](const SecPtr &Sec) { return Sec->Name == Name; }); + if (It == Sections.end()) + return createStringError(errc::invalid_argument, "section '%s' not found", + Name.str().c_str()); + return updateSectionData(*It, Data); +} + +Error Object::updateSectionData(SectionBase &S, ArrayRef<uint8_t> Data) { + auto It = llvm::find_if(Sections, + [&](const SecPtr &Sec) { return Sec.get() == &S; }); + assert(It != Sections.end() && "The section should belong to the object"); + return updateSectionData(*It, Data); +} + Error Object::removeSections( bool AllowBrokenLinks, std::function<bool(const SectionBase &)> ToRemove) { diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h index 6ccf853..d8f79a4 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObject.h +++ b/llvm/lib/ObjCopy/ELF/ELFObject.h @@ -549,6 +549,7 @@ public: virtual void replaceSectionReferences(const DenseMap<SectionBase *, SectionBase *> &); virtual bool hasContents() const { return false; } + virtual ArrayRef<uint8_t> getContents() const { return {}; } // Notify the section that it is subject to removal. virtual void onRemove(); @@ -619,6 +620,8 @@ public: bool hasContents() const override { return Type != ELF::SHT_NOBITS && Type != ELF::SHT_NULL; } + ArrayRef<uint8_t> getContents() const override { return Contents; } + void restoreSymTabLink(SymbolTableSection &SymTab) override; }; @@ -654,6 +657,7 @@ public: Error accept(SectionVisitor &Sec) const override; Error accept(MutableSectionVisitor &Visitor) override; bool hasContents() const override { return true; } + ArrayRef<uint8_t> getContents() const override { return Data; } }; class CompressedSection : public SectionBase { @@ -1164,6 +1168,8 @@ private: return Sec.Flags & ELF::SHF_ALLOC; }; + Error updateSectionData(SecPtr &Sec, ArrayRef<uint8_t> Data); + public: template <class T> using ConstRange = iterator_range<pointee_iterator< @@ -1206,6 +1212,7 @@ public: const auto &getUpdatedSections() const { return UpdatedSections; } Error updateSection(StringRef Name, ArrayRef<uint8_t> Data); + Error updateSectionData(SectionBase &S, ArrayRef<uint8_t> Data); SectionBase *findSection(StringRef Name) { auto SecIt = |
