diff options
Diffstat (limited to 'llvm/tools/llvm-objcopy/ELF')
-rw-r--r-- | llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp | 55 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/ELF/Object.cpp | 173 | ||||
-rw-r--r-- | llvm/tools/llvm-objcopy/ELF/Object.h | 7 |
3 files changed, 129 insertions, 106 deletions
diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp index a0cfd9a5ff86..66953f9ef0d5 100644 --- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -11,7 +11,6 @@ #include "CopyConfig.h" #include "Object.h" #include "llvm-objcopy.h" - #include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Optional.h" @@ -32,6 +31,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Memory.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -83,6 +83,8 @@ uint64_t getNewShfFlags(SectionFlag AllFlags) { NewFlags |= ELF::SHF_MERGE; if (AllFlags & SectionFlag::SecStrings) NewFlags |= ELF::SHF_STRINGS; + if (AllFlags & SectionFlag::SecExclude) + NewFlags |= ELF::SHF_EXCLUDE; return NewFlags; } @@ -90,10 +92,11 @@ static uint64_t getSectionFlagsPreserveMask(uint64_t OldFlags, uint64_t NewFlags) { // Preserve some flags which should not be dropped when setting flags. // Also, preserve anything OS/processor dependant. - const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE | - ELF::SHF_GROUP | ELF::SHF_LINK_ORDER | - ELF::SHF_MASKOS | ELF::SHF_MASKPROC | - ELF::SHF_TLS | ELF::SHF_INFO_LINK; + const uint64_t PreserveMask = + (ELF::SHF_COMPRESSED | ELF::SHF_GROUP | ELF::SHF_LINK_ORDER | + ELF::SHF_MASKOS | ELF::SHF_MASKPROC | ELF::SHF_TLS | + ELF::SHF_INFO_LINK) & + ~ELF::SHF_EXCLUDE; return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask); } @@ -267,7 +270,7 @@ static Error splitDWOToFile(const CopyConfig &Config, const Reader &Reader, auto OnlyKeepDWOPred = [&DWOFile](const SectionBase &Sec) { return onlyKeepDWOPred(*DWOFile, Sec); }; - if (Error E = DWOFile->removeSections(Config.AllowBrokenLinks, + if (Error E = DWOFile->removeSections(Config.AllowBrokenLinks, OnlyKeepDWOPred)) return E; if (Config.OutputArch) { @@ -285,7 +288,7 @@ static Error dumpSectionToFile(StringRef SecName, StringRef Filename, Object &Obj) { for (auto &Sec : Obj.sections()) { if (Sec.Name == SecName) { - if (Sec.OriginalData.empty()) + if (Sec.Type == SHT_NOBITS) return createStringError(object_error::parse_failed, "cannot dump section '%s': it has no contents", SecName.str().c_str()); @@ -387,7 +390,7 @@ static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { const auto I = Config.SymbolsToRename.find(Sym.Name); if (I != Config.SymbolsToRename.end()) - Sym.Name = I->getValue(); + Sym.Name = std::string(I->getValue()); if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION) Sym.Name = (Config.SymbolsPrefix + Sym.Name).str(); @@ -417,6 +420,9 @@ static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { if (Config.StripAll || Config.StripAllGNU) return true; + if (Config.StripDebug && Sym.Type == STT_FILE) + return true; + if (Config.SymbolsToRemove.matches(Sym.Name)) return true; @@ -572,11 +578,11 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { } if (Config.CompressionType != DebugCompressionType::None) - replaceDebugSections(Obj, RemovePred, isCompressable, + replaceDebugSections(Obj, RemovePred, isCompressable, [&Config, &Obj](const SectionBase *S) { return &Obj.addSection<CompressedSection>( *S, Config.CompressionType); - }); + }); else if (Config.DecompressDebugSections) replaceDebugSections( Obj, RemovePred, @@ -598,7 +604,9 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { // system. The only priority is that keeps/copies overrule removes. static Error handleArgs(const CopyConfig &Config, Object &Obj, const Reader &Reader, ElfType OutputElfType) { - + if (Config.StripSwiftSymbols) + return createStringError(llvm::errc::invalid_argument, + "option not supported by llvm-objcopy for ELF"); if (!Config.SplitDWO.empty()) if (Error E = splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType)) @@ -609,6 +617,15 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj, Obj.OSABI = Config.OutputArch.getValue().OSABI; } + // Dump sections before add/remove for compatibility with GNU objcopy. + for (StringRef Flag : Config.DumpSection) { + StringRef SectionName; + StringRef FileName; + std::tie(SectionName, FileName) = Flag.split('='); + if (Error E = dumpSectionToFile(SectionName, FileName, Obj)) + return E; + } + // It is important to remove the sections first. For example, we want to // remove the relocation sections before removing the symbols. That allows // us to avoid reporting the inappropriate errors about removing symbols @@ -624,7 +641,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj, const auto Iter = Config.SectionsToRename.find(Sec.Name); if (Iter != Config.SectionsToRename.end()) { const SectionRename &SR = Iter->second; - Sec.Name = SR.NewName; + Sec.Name = std::string(SR.NewName); if (SR.NewFlags.hasValue()) setSectionFlagsAndType(Sec, SR.NewFlags.getValue()); } @@ -717,18 +734,16 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj, NewSection.Type = SHT_NOTE; } - for (const auto &Flag : Config.DumpSection) { - std::pair<StringRef, StringRef> SecPair = Flag.split("="); - StringRef SecName = SecPair.first; - StringRef File = SecPair.second; - if (Error E = dumpSectionToFile(SecName, File, Obj)) - return E; - } - if (!Config.AddGnuDebugLink.empty()) Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink, Config.GnuDebugLinkCRC32); + // If the symbol table was previously removed, we need to create a new one + // before adding new symbols. + if (!Obj.SymbolTable && !Config.ELF->SymbolsToAdd.empty()) { + Obj.addNewSymbolTable(); + } + for (const NewSymbolInfo &SI : Config.ELF->SymbolsToAdd) { SectionBase *Sec = Obj.findSection(SI.SectionName); uint64_t Value = Sec ? Sec->Addr + SI.Value : SI.Value; diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp index ad53c75663ec..e15fb24f4c42 100644 --- a/llvm/tools/llvm-objcopy/ELF/Object.cpp +++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp @@ -65,6 +65,7 @@ void SectionBase::finalize() {} void SectionBase::markSymbols() {} void SectionBase::replaceSectionReferences( const DenseMap<SectionBase *, SectionBase *> &) {} +void SectionBase::onRemove() {} template <class ELFT> void ELFWriter<ELFT>::writeShdr(const SectionBase &Sec) { uint8_t *B = Buf.getBufferStart() + Sec.HeaderOffset; @@ -111,7 +112,9 @@ void ELFSectionSizer<ELFT>::visit(RelocationSection &Sec) { template <class ELFT> void ELFSectionSizer<ELFT>::visit(GnuDebugLinkSection &Sec) {} -template <class ELFT> void ELFSectionSizer<ELFT>::visit(GroupSection &Sec) {} +template <class ELFT> void ELFSectionSizer<ELFT>::visit(GroupSection &Sec) { + Sec.Size = sizeof(Elf_Word) + Sec.GroupMembers.size() * sizeof(Elf_Word); +} template <class ELFT> void ELFSectionSizer<ELFT>::visit(SectionIndexSection &Sec) {} @@ -605,6 +608,7 @@ static bool isValidReservedSectionIndex(uint16_t Index, uint16_t Machine) { if (Machine == EM_HEXAGON) { switch (Index) { case SHN_HEXAGON_SCOMMON: + case SHN_HEXAGON_SCOMMON_1: case SHN_HEXAGON_SCOMMON_2: case SHN_HEXAGON_SCOMMON_4: case SHN_HEXAGON_SCOMMON_8: @@ -741,7 +745,7 @@ void SymbolTableSection::prepareForLayout() { // Reserve proper amount of space in section index table, so we can // layout sections correctly. We will fill the table with correct // indexes later in fillShdnxTable. - if (SectionIndexTable) + if (SectionIndexTable) SectionIndexTable->reserve(Symbols.size()); // Add all of our strings to SymbolNames so that SymbolNames has the right @@ -963,8 +967,24 @@ Error Section::removeSectionReferences( } void GroupSection::finalize() { - this->Info = Sym->Index; - this->Link = SymTab->Index; + this->Info = Sym ? Sym->Index : 0; + this->Link = SymTab ? SymTab->Index : 0; +} + +Error GroupSection::removeSectionReferences( + bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) { + if (ToRemove(SymTab)) { + if (!AllowBrokenLinks) + return createStringError( + llvm::errc::invalid_argument, + "section '.symtab' cannot be removed because it is " + "referenced by the group section '%s'", + this->Name.data()); + SymTab = nullptr; + Sym = nullptr; + } + llvm::erase_if(GroupMembers, ToRemove); + return Error::success(); } Error GroupSection::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) { @@ -988,6 +1008,13 @@ void GroupSection::replaceSectionReferences( Sec = To; } +void GroupSection::onRemove() { + // As the header section of the group is removed, drop the Group flag in its + // former members. + for (SectionBase *Sec : GroupMembers) + Sec->Flags &= ~SHF_GROUP; +} + void Section::initialize(SectionTableRef SecTable) { if (Link == ELF::SHN_UNDEF) return; @@ -1101,14 +1128,6 @@ static bool compareSegmentsByOffset(const Segment *A, const Segment *B) { return A->Index < B->Index; } -static bool compareSegmentsByPAddr(const Segment *A, const Segment *B) { - if (A->PAddr < B->PAddr) - return true; - if (A->PAddr > B->PAddr) - return false; - return A->Index < B->Index; -} - void BasicELFBuilder::initFileHeader() { Obj->Flags = 0x0; Obj->Type = ET_REL; @@ -1241,7 +1260,7 @@ std::unique_ptr<Object> IHexELFBuilder::build() { template <class ELFT> void ELFBuilder<ELFT>::setParentSegment(Segment &Child) { for (Segment &Parent : Obj.segments()) { // Every segment will overlap with itself but we don't want a segment to - // be it's own parent so we avoid that situation. + // be its own parent so we avoid that situation. if (&Child != &Parent && segmentOverlapsSegment(Child, Parent)) { // We want a canonical "most parental" segment but this requires // inspecting the ParentSegment. @@ -1330,18 +1349,20 @@ void ELFBuilder<ELFT>::initGroupSection(GroupSection *GroupSec) { error("invalid alignment " + Twine(GroupSec->Align) + " of group section '" + GroupSec->Name + "'"); SectionTableRef SecTable = Obj.sections(); - auto SymTab = SecTable.template getSectionOfType<SymbolTableSection>( - GroupSec->Link, - "link field value '" + Twine(GroupSec->Link) + "' in section '" + - GroupSec->Name + "' is invalid", - "link field value '" + Twine(GroupSec->Link) + "' in section '" + - GroupSec->Name + "' is not a symbol table"); - Symbol *Sym = SymTab->getSymbolByIndex(GroupSec->Info); - if (!Sym) - error("info field value '" + Twine(GroupSec->Info) + "' in section '" + - GroupSec->Name + "' is not a valid symbol index"); - GroupSec->setSymTab(SymTab); - GroupSec->setSymbol(Sym); + if (GroupSec->Link != SHN_UNDEF) { + auto SymTab = SecTable.template getSectionOfType<SymbolTableSection>( + GroupSec->Link, + "link field value '" + Twine(GroupSec->Link) + "' in section '" + + GroupSec->Name + "' is invalid", + "link field value '" + Twine(GroupSec->Link) + "' in section '" + + GroupSec->Name + "' is not a symbol table"); + Symbol *Sym = SymTab->getSymbolByIndex(GroupSec->Info); + if (!Sym) + error("info field value '" + Twine(GroupSec->Info) + "' in section '" + + GroupSec->Name + "' is not a valid symbol index"); + GroupSec->setSymTab(SymTab); + GroupSec->setSymbol(Sym); + } if (GroupSec->Contents.size() % sizeof(ELF::Elf32_Word) || GroupSec->Contents.empty()) error("the content of the section " + GroupSec->Name + " is malformed"); @@ -1520,7 +1541,7 @@ template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() { continue; } auto &Sec = makeSection(Shdr); - Sec.Name = unwrapOrError(ElfFile.getSectionName(&Shdr)); + Sec.Name = std::string(unwrapOrError(ElfFile.getSectionName(&Shdr))); Sec.Type = Sec.OriginalType = Shdr.sh_type; Sec.Flags = Sec.OriginalFlags = Shdr.sh_flags; Sec.Addr = Shdr.sh_addr; @@ -1567,27 +1588,7 @@ template <class ELFT> void ELFBuilder<ELFT>::readSections(bool EnsureSymtab) { Obj.SymbolTable->initialize(Obj.sections()); initSymbolTable(Obj.SymbolTable); } else if (EnsureSymtab) { - // Reuse an existing SHT_STRTAB section if it exists. - StringTableSection *StrTab = nullptr; - for (auto &Sec : Obj.sections()) { - if (Sec.Type == ELF::SHT_STRTAB && !(Sec.Flags & SHF_ALLOC)) { - StrTab = static_cast<StringTableSection *>(&Sec); - - // Prefer a string table that is not the section header string table, if - // such a table exists. - if (Obj.SectionNames != &Sec) - break; - } - } - if (!StrTab) - StrTab = &Obj.addSection<StringTableSection>(); - - SymbolTableSection &SymTab = Obj.addSection<SymbolTableSection>(); - SymTab.Name = ".symtab"; - SymTab.Link = StrTab->Index; - SymTab.initialize(Obj.sections()); - SymTab.addSymbol("", 0, 0, nullptr, 0, 0, 0, 0); - Obj.SymbolTable = &SymTab; + Obj.addNewSymbolTable(); } // Now that all sections and symbols have been added we can add @@ -1846,6 +1847,7 @@ Error Object::removeSections(bool AllowBrokenLinks, for (auto &RemoveSec : make_range(Iter, std::end(Sections))) { for (auto &Segment : Segments) Segment->removeSection(RemoveSec.get()); + RemoveSec->onRemove(); RemoveSections.insert(RemoveSec.get()); } @@ -1878,6 +1880,33 @@ Error Object::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) { return Error::success(); } +void Object::addNewSymbolTable() { + assert(!SymbolTable && "Object must not has a SymbolTable."); + + // Reuse an existing SHT_STRTAB section if it exists. + StringTableSection *StrTab = nullptr; + for (SectionBase &Sec : sections()) { + if (Sec.Type == ELF::SHT_STRTAB && !(Sec.Flags & SHF_ALLOC)) { + StrTab = static_cast<StringTableSection *>(&Sec); + + // Prefer a string table that is not the section header string table, if + // such a table exists. + if (SectionNames != &Sec) + break; + } + } + if (!StrTab) + StrTab = &addSection<StringTableSection>(); + + SymbolTableSection &SymTab = addSection<SymbolTableSection>(); + SymTab.Name = ".symtab"; + SymTab.Link = StrTab->Index; + SymTab.initialize(sections()); + SymTab.addSymbol("", 0, 0, nullptr, 0, 0, 0, 0); + + SymbolTable = &SymTab; +} + void Object::sortSections() { // Use stable_sort to maintain the original ordering as closely as possible. llvm::stable_sort(Sections, [](const SecPtr &A, const SecPtr &B) { @@ -1902,8 +1931,7 @@ static void orderSegments(std::vector<Segment *> &Segments) { // returns an Offset one past the end of the last segment. static uint64_t layoutSegments(std::vector<Segment *> &Segments, uint64_t Offset) { - assert(std::is_sorted(std::begin(Segments), std::end(Segments), - compareSegmentsByOffset)); + assert(llvm::is_sorted(Segments, compareSegmentsByOffset)); // The only way a segment should move is if a section was between two // segments and that section was removed. If that section isn't in a segment // then it's acceptable, but not ideal, to simply move it to after the @@ -2225,56 +2253,29 @@ Error BinaryWriter::write() { } Error BinaryWriter::finalize() { - // We need a temporary list of segments that has a special order to it - // so that we know that anytime ->ParentSegment is set that segment has - // already had it's offset properly set. We only want to consider the segments - // that will affect layout of allocated sections so we only add those. - std::vector<Segment *> OrderedSegments; - for (const SectionBase &Sec : Obj.allocSections()) - if (Sec.ParentSegment != nullptr) - OrderedSegments.push_back(Sec.ParentSegment); - - // For binary output, we're going to use physical addresses instead of - // virtual addresses, since a binary output is used for cases like ROM - // loading and physical addresses are intended for ROM loading. - // However, if no segment has a physical address, we'll fallback to using - // virtual addresses for all. - if (all_of(OrderedSegments, - [](const Segment *Seg) { return Seg->PAddr == 0; })) - for (Segment *Seg : OrderedSegments) - Seg->PAddr = Seg->VAddr; - - llvm::stable_sort(OrderedSegments, compareSegmentsByPAddr); - - // Because we add a ParentSegment for each section we might have duplicate - // segments in OrderedSegments. If there were duplicates then layoutSegments - // would do very strange things. - auto End = - std::unique(std::begin(OrderedSegments), std::end(OrderedSegments)); - OrderedSegments.erase(End, std::end(OrderedSegments)); - // Compute the section LMA based on its sh_offset and the containing segment's - // p_offset and p_paddr. Also compute the minimum LMA of all sections as - // MinAddr. In the output, the contents between address 0 and MinAddr will be - // skipped. + // p_offset and p_paddr. Also compute the minimum LMA of all non-empty + // sections as MinAddr. In the output, the contents between address 0 and + // MinAddr will be skipped. uint64_t MinAddr = UINT64_MAX; for (SectionBase &Sec : Obj.allocSections()) { if (Sec.ParentSegment != nullptr) Sec.Addr = Sec.Offset - Sec.ParentSegment->Offset + Sec.ParentSegment->PAddr; - MinAddr = std::min(MinAddr, Sec.Addr); + if (Sec.Size > 0) + MinAddr = std::min(MinAddr, Sec.Addr); } // Now that every section has been laid out we just need to compute the total // file size. This might not be the same as the offset returned by // layoutSections, because we want to truncate the last segment to the end of - // its last section, to match GNU objcopy's behaviour. + // its last non-empty section, to match GNU objcopy's behaviour. TotalSize = 0; - for (SectionBase &Sec : Obj.allocSections()) { - Sec.Offset = Sec.Addr - MinAddr; - if (Sec.Type != SHT_NOBITS) + for (SectionBase &Sec : Obj.allocSections()) + if (Sec.Type != SHT_NOBITS && Sec.Size > 0) { + Sec.Offset = Sec.Addr - MinAddr; TotalSize = std::max(TotalSize, Sec.Offset + Sec.Size); - } + } if (Error E = Buf.allocate(TotalSize)) return E; diff --git a/llvm/tools/llvm-objcopy/ELF/Object.h b/llvm/tools/llvm-objcopy/ELF/Object.h index 97702a66bc47..ed89e916b838 100644 --- a/llvm/tools/llvm-objcopy/ELF/Object.h +++ b/llvm/tools/llvm-objcopy/ELF/Object.h @@ -424,6 +424,8 @@ public: virtual void markSymbols(); virtual void replaceSectionReferences(const DenseMap<SectionBase *, SectionBase *> &); + // Notify the section that it is subject to removal. + virtual void onRemove(); }; class Segment { @@ -799,10 +801,14 @@ public: void accept(SectionVisitor &) const override; void accept(MutableSectionVisitor &Visitor) override; void finalize() override; + Error removeSectionReferences( + bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove) override; Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; void markSymbols() override; void replaceSectionReferences( const DenseMap<SectionBase *, SectionBase *> &FromTo) override; + void onRemove() override; static bool classof(const SectionBase *S) { return S->OriginalType == ELF::SHT_GROUP; @@ -1066,6 +1072,7 @@ public: Ptr->Index = Sections.size(); return *Ptr; } + void addNewSymbolTable(); Segment &addSegment(ArrayRef<uint8_t> Data) { Segments.emplace_back(std::make_unique<Segment>(Data)); return *Segments.back(); |