aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp')
-rw-r--r--llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp168
1 files changed, 163 insertions, 5 deletions
diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index 075455c03415..5aa0079f3fbc 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -10,7 +10,6 @@
#include "ELFObject.h"
#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
@@ -28,16 +27,12 @@
#include "llvm/Support/Errc.h"
#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"
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <functional>
-#include <iterator>
#include <memory>
#include <string>
#include <system_error>
@@ -614,6 +609,113 @@ 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) {
+ using Elf_Nhdr = typename ELFT::Nhdr;
+ using Elf_Note = typename ELFT::Note;
+ 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) {
@@ -745,6 +847,56 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
}
}
+ if (!Config.ChangeSectionAddress.empty()) {
+ if (Obj.Type != ELF::ET_REL)
+ return createStringError(
+ object_error::invalid_file_type,
+ "cannot change section address in a non-relocatable file");
+
+ StringMap<AddressUpdate> SectionsToUpdateAddress;
+ for (const SectionPatternAddressUpdate &PatternUpdate :
+ make_range(Config.ChangeSectionAddress.rbegin(),
+ Config.ChangeSectionAddress.rend())) {
+ for (SectionBase &Sec : Obj.sections()) {
+ if (PatternUpdate.SectionPattern.matches(Sec.Name) &&
+ SectionsToUpdateAddress.try_emplace(Sec.Name, PatternUpdate.Update)
+ .second) {
+ if (PatternUpdate.Update.Kind == AdjustKind::Subtract &&
+ Sec.Addr < PatternUpdate.Update.Value) {
+ return createStringError(
+ errc::invalid_argument,
+ "address 0x" + Twine::utohexstr(Sec.Addr) +
+ " cannot be decreased by 0x" +
+ Twine::utohexstr(PatternUpdate.Update.Value) +
+ ". The result would underflow");
+ }
+ if (PatternUpdate.Update.Kind == AdjustKind::Add &&
+ Sec.Addr > std::numeric_limits<uint64_t>::max() -
+ PatternUpdate.Update.Value) {
+ return createStringError(
+ errc::invalid_argument,
+ "address 0x" + Twine::utohexstr(Sec.Addr) +
+ " cannot be increased by 0x" +
+ Twine::utohexstr(PatternUpdate.Update.Value) +
+ ". The result would overflow");
+ }
+
+ switch (PatternUpdate.Update.Kind) {
+ case (AdjustKind::Set):
+ Sec.Addr = PatternUpdate.Update.Value;
+ break;
+ case (AdjustKind::Subtract):
+ Sec.Addr -= PatternUpdate.Update.Value;
+ break;
+ case (AdjustKind::Add):
+ Sec.Addr += PatternUpdate.Update.Value;
+ break;
+ }
+ }
+ }
+ }
+ }
+
if (Config.OnlyKeepDebug)
for (auto &Sec : Obj.sections())
if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE)
@@ -754,6 +906,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 =