summaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-objcopy/ELF
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-objcopy/ELF')
-rw-r--r--llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp55
-rw-r--r--llvm/tools/llvm-objcopy/ELF/Object.cpp173
-rw-r--r--llvm/tools/llvm-objcopy/ELF/Object.h7
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();