diff options
author | Leonard Chan <leonardchan@google.com> | 2021-10-20 13:03:49 -0700 |
---|---|---|
committer | Leonard Chan <leonardchan@google.com> | 2021-11-16 14:10:40 -0800 |
commit | 25bcd94234530955c58c6530a9271c813827637c (patch) | |
tree | cc98771ab9e1d79ef5b8d81cca89cf5c406a07fc /llvm/tools/llvm-objcopy/ELF/Object.cpp | |
parent | 4c2cf3a314d9131b1b288e7c8ab0c75ac1b2be1d (diff) | |
download | llvm-25bcd94234530955c58c6530a9271c813827637c.zip llvm-25bcd94234530955c58c6530a9271c813827637c.tar.gz llvm-25bcd94234530955c58c6530a9271c813827637c.tar.bz2 |
[llvm-objcopy] Add --update-section
This is another attempt at D59351 which attempted to add --update-section, but
with some heuristics for adjusting segment/section offsets/sizes in the event
the data copied into the section is larger than the original size of the section.
We are opting to not support this case. GNU's objcopy was able to do this because
the linker and objcopy are tightly coupled enough that segment reformatting was
simpler. This is not the case with llvm-objcopy and lld where they like to be separated.
This will attempt to copy data into the section without changing any other
properties of the parent segment (if the section is part of one).
Differential Revision: https://reviews.llvm.org/D112116
Diffstat (limited to 'llvm/tools/llvm-objcopy/ELF/Object.cpp')
-rw-r--r-- | llvm/tools/llvm-objcopy/ELF/Object.cpp | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp index 0d4f164..3db5028e 100644 --- a/llvm/tools/llvm-objcopy/ELF/Object.cpp +++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp @@ -2107,6 +2107,17 @@ template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() { Size); } + for (auto it : Obj.getUpdatedSections()) { + SectionBase *Sec = it.first; + ArrayRef<uint8_t> Data = it.second; + + auto *Parent = Sec->ParentSegment; + assert(Parent && "This section should've been part of a segment."); + uint64_t Offset = + Sec->OriginalOffset - Parent->OriginalOffset + Parent->Offset; + llvm::copy(Data, Buf->getBufferStart() + Offset); + } + // Iterate over removed sections and overwrite their old data with zeroes. for (auto &Sec : Obj.removedSections()) { Segment *Parent = Sec.ParentSegment; @@ -2124,6 +2135,37 @@ 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()) + return createStringError( + errc::invalid_argument, + "section '%s' can't be updated because it does not have contents", + Name.str().c_str()); + + if (Data.size() > OldSec->Size && OldSec->ParentSegment) + return createStringError(errc::invalid_argument, + "cannot fit data of size %zu into section '%s' " + "with size %zu that is part of a segment", + Data.size(), Name.str().c_str(), OldSec->Size); + + if (!OldSec->ParentSegment) { + *It = std::make_unique<OwnedDataSection>(*OldSec, Data); + } else { + // The segment writer will be in charge of updating these contents. + OldSec->Size = Data.size(); + UpdatedSections[OldSec] = Data; + } + + return Error::success(); +} + Error Object::removeSections( bool AllowBrokenLinks, std::function<bool(const SectionBase &)> ToRemove) { |