[llvm] [llvm-objcopy][ELF] Add an option to remove notes (PR #118739)

Igor Kudrin via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 22 20:22:46 PST 2025


https://github.com/igorkudrin updated https://github.com/llvm/llvm-project/pull/118739

>From 24308b26df6af7c9e027db9ef637a8da75fdf93f Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Wed, 27 Nov 2024 22:31:05 -0800
Subject: [PATCH 01/21] [llvm-objcopy][ELF] Add an option to remove notes

This adds an option `--remove-note` to selectively delete notes in an
ELF file. For now, it is expected to be useful for editing core dump
files; in particular, it searches for the notes in `PT_NOTE` segments
and does not handle nested segments. The implementation can be extended
later as needed.
---
 llvm/include/llvm/ObjCopy/ELF/ELFConfig.h     |  9 ++
 llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp           | 96 ++++++++++++++++++
 llvm/lib/ObjCopy/ELF/ELFObject.cpp            | 21 ++++
 llvm/lib/ObjCopy/ELF/ELFObject.h              |  5 +
 .../tools/llvm-objcopy/ELF/remove-note.test   | 98 +++++++++++++++++++
 llvm/tools/llvm-objcopy/ObjcopyOptions.cpp    | 39 ++++++++
 llvm/tools/llvm-objcopy/ObjcopyOpts.td        |  4 +
 7 files changed, 272 insertions(+)
 create mode 100644 llvm/test/tools/llvm-objcopy/ELF/remove-note.test

diff --git a/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h b/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h
index 59960b65307430..01a8762cfb9c37 100644
--- a/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h
+++ b/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h
@@ -15,6 +15,12 @@
 namespace llvm {
 namespace objcopy {
 
+// Note to remove info specified by --remove-note option.
+struct RemoveNoteInfo {
+  StringRef Name;
+  uint32_t TypeId;
+};
+
 // ELF specific configuration for copying/stripping a single file.
 struct ELFConfig {
   uint8_t NewSymbolVisibility = (uint8_t)ELF::STV_DEFAULT;
@@ -31,6 +37,9 @@ struct ELFConfig {
   bool KeepFileSymbols = false;
   bool LocalizeHidden = false;
   bool VerifyNoteSections = true;
+
+  // Notes specified by --remove-note option.
+  SmallVector<RemoveNoteInfo, 0> NotesToRemove;
 };
 
 } // namespace objcopy
diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index 4793651f1d4e0b..1df64b0b7ce886 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -609,6 +609,97 @@ static void addSymbol(Object &Obj, const NewSymbolInfo &SymInfo,
       Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0);
 }
 
+template <class ELFT>
+static Error removeNoteImpl(Object &Obj,
+                            ArrayRef<RemoveNoteInfo> NotesToRemove) {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT);
+  for (Segment &Seg : Obj.segments()) {
+    // TODO: Support nested segments
+    if (Seg.Type != PT_NOTE || Seg.ParentSegment)
+      continue;
+
+    // Find chunks of the segment data to remove
+    struct DeletedRange {
+      uint64_t OldFrom;
+      uint64_t OldTo;
+      uint64_t NewOffset;
+    };
+    std::vector<DeletedRange> DataToRemove;
+    ArrayRef<uint8_t> OldData = Seg.getContents();
+    size_t Align = std::max<size_t>(4, Seg.Align);
+    uint64_t Offset = 0;
+    while (Offset + sizeof(Elf_Nhdr) <= OldData.size()) {
+      auto Nhdr = reinterpret_cast<const Elf_Nhdr *>(OldData.data() + Offset);
+      size_t FullSize = Nhdr->getSize(Align);
+      if (Offset + FullSize > OldData.size())
+        break;
+      Elf_Note Note(*Nhdr);
+      if (llvm::any_of(NotesToRemove, [&](const RemoveNoteInfo &NoteInfo) {
+            return NoteInfo.TypeId == Note.getType() &&
+                   (NoteInfo.Name.empty() || NoteInfo.Name == Note.getName());
+          }))
+        DataToRemove.push_back({Offset, Offset + FullSize, 0});
+      Offset += FullSize;
+    }
+    if (DataToRemove.empty())
+      continue;
+
+    // Prepare the new segment data
+    std::vector<uint8_t> NewData;
+    NewData.reserve(OldData.size());
+    Offset = 0;
+    for (auto &RemRange : DataToRemove) {
+      if (Offset < RemRange.OldFrom) {
+        auto Slice = OldData.slice(Offset, RemRange.OldFrom - Offset);
+        NewData.insert(NewData.end(), Slice.begin(), Slice.end());
+      }
+      RemRange.NewOffset = NewData.size();
+      Offset = RemRange.OldTo;
+    }
+    if (Offset < OldData.size()) {
+      auto Slice = OldData.slice(Offset);
+      NewData.insert(NewData.end(), Slice.begin(), Slice.end());
+    }
+
+    auto CalculateNewOffset = [&](uint64_t SecOffset) {
+      uint64_t Offset = SecOffset - Seg.Offset;
+      auto It =
+          llvm::upper_bound(DataToRemove, Offset,
+                            [](const uint64_t &Off, const DeletedRange &Range) {
+                              return Off < Range.OldFrom;
+                            });
+      if (It != DataToRemove.begin()) {
+        --It;
+        Offset = (Offset > It->OldTo) ? (Offset - It->OldTo + It->NewOffset)
+                                      : It->NewOffset;
+      }
+      return Offset + Seg.Offset;
+    };
+
+    // Remap the segment's sections
+    DenseMap<const SectionBase *, std::pair<uint64_t, uint64_t>> Mapping;
+    for (const SectionBase *Sec : Seg.Sections) {
+      uint64_t NewOffset = CalculateNewOffset(Sec->Offset);
+      uint64_t NewSize =
+          CalculateNewOffset(Sec->Offset + Sec->Size) - NewOffset;
+      Mapping.try_emplace(Sec, NewOffset, NewSize);
+    }
+
+    Obj.updateSegmentData(Seg, std::move(NewData), Mapping);
+  }
+  return Error::success();
+}
+
+static Error removeNote(Object &Obj, endianness Endianness,
+                        ArrayRef<RemoveNoteInfo> NotesToRemove) {
+  // Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the
+  // header, so the parsers are the same.
+  if (Endianness == endianness::little)
+    return removeNoteImpl<ELF64LE>(Obj, NotesToRemove);
+  else
+    return removeNoteImpl<ELF64BE>(Obj, NotesToRemove);
+}
+
 static Error
 handleUserSection(const NewSectionInfo &NewSection,
                   function_ref<Error(StringRef, ArrayRef<uint8_t>)> F) {
@@ -799,6 +890,11 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
                      ? endianness::little
                      : endianness::big;
 
+  if (!ELFConfig.NotesToRemove.empty()) {
+    if (Error Err = removeNote(Obj, E, ELFConfig.NotesToRemove))
+      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 01c2f24629077a..9f460f685706c8 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -2308,6 +2308,27 @@ Error Object::addNewSymbolTable() {
   return Error::success();
 }
 
+void Object::updateSegmentData(
+    Segment &S, std::vector<uint8_t> NewSegmentData,
+    const DenseMap<const SectionBase *, std::pair<uint64_t, uint64_t>>
+        &SectionMapping) {
+  auto It =
+      UpdatedSegments.insert_or_assign(&S, std::move(NewSegmentData)).first;
+  S.Contents = It->second;
+  S.FileSize = S.Contents.size();
+  if (S.MemSize)
+    S.MemSize = S.FileSize;
+  assert(SectionMapping.size() == S.Sections.size());
+  for (const auto &SM : SectionMapping) {
+    assert(SM.first->ParentSegment == &S && S.Sections.count(SM.first));
+    assert(SM.second.first >= S.Offset);
+    assert((SM.second.first + SM.second.second) <= (S.Offset + S.FileSize));
+    SectionBase *MutSec = const_cast<SectionBase *>(SM.first);
+    MutSec->Offset = SM.second.first;
+    MutSec->Size = SM.second.second;
+  }
+}
+
 // Orders segments such that if x = y->ParentSegment then y comes before x.
 static void orderSegments(std::vector<Segment *> &Segments) {
   llvm::stable_sort(Segments, compareSegmentsByOffset);
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h
index 6ccf85387131e4..5e16d4c0c1885a 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.h
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.h
@@ -1159,6 +1159,7 @@ class Object {
   std::vector<SegPtr> Segments;
   std::vector<SecPtr> RemovedSections;
   DenseMap<SectionBase *, std::vector<uint8_t>> UpdatedSections;
+  DenseMap<Segment *, std::vector<uint8_t>> UpdatedSegments;
 
   static bool sectionIsAlloc(const SectionBase &Sec) {
     return Sec.Flags & ELF::SHF_ALLOC;
@@ -1234,6 +1235,10 @@ class Object {
     Segments.emplace_back(std::make_unique<Segment>(Data));
     return *Segments.back();
   }
+  void updateSegmentData(
+      Segment &S, std::vector<uint8_t> NewSegmentData,
+      const DenseMap<const SectionBase *, std::pair<uint64_t, uint64_t>>
+          &SectionMapping);
   bool isRelocatable() const {
     return (Type != ELF::ET_DYN && Type != ELF::ET_EXEC) || MustBeRelocatable;
   }
diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
new file mode 100644
index 00000000000000..b24538e26d019e
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
@@ -0,0 +1,98 @@
+# RUN: not llvm-objcopy --remove-note= - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID
+# RUN: not llvm-objcopy --remove-note=/1 - 2>&1 | FileCheck %s --check-prefix=ERR-EMPTYNAME
+# RUN: not llvm-objcopy --remove-note=CORE/1/2 - 2>&1 | FileCheck %s --check-prefix=ERR-INVNUM1
+# RUN: not llvm-objcopy --remove-note=Notanumber - 2>&1 | FileCheck %s --check-prefix=ERR-INVNUM2
+# RUN: not llvm-objcopy --remove-note=CORE/Notanumber - 2>&1 | FileCheck %s --check-prefix=ERR-INVNUM2
+
+# ERR-NOTYPEID: error: bad format for --remove-note, missing type_id
+# ERR-EMPTYNAME: error: bad format for --remove-note, note name is empty
+# ERR-INVNUM1: error: bad note type_id for --remove-note: '1/2'
+# ERR-INVNUM2: error: bad note type_id for --remove-note: 'Notanumber'
+
+# RUN: yaml2obj -D ALIGN=8 %s -o - \
+# RUN:   | llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/0x03 - - \
+# RUN:   | llvm-readobj --segments --sections --notes - \
+# RUN:   | FileCheck %s -D#SIZE=64
+
+# RUN: yaml2obj -D ALIGN=4 %s -o - \
+# RUN:   | llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/0x03 - - \
+# RUN:   | llvm-readobj --segments --sections --notes - \
+# RUN:   | FileCheck %s -D#SIZE=48
+
+# CHECK:      Sections [
+# CHECK:        Section {
+# CHECK:          Name: .note
+# CHECK-NEXT:     Type: SHT_NOTE
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Offset: [[OFFSET:0x.+]]
+# CHECK-NEXT:     Size: [[#%d,SIZE]]
+
+# CHECK:      ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_NOTE
+# CHECK-NEXT:     Offset: [[OFFSET]]
+# CHECK-NEXT:     VirtualAddress: 0x0
+# CHECK-NEXT:     PhysicalAddress: 0x0
+# CHECK-NEXT:     FileSize: [[#%d,SIZE]]
+# CHECK-NEXT:     MemSize: 0
+
+# CHECK:      NoteSections [
+# CHECK-NEXT:   NoteSection {
+# CHECK-NEXT:     Name:
+# CHECK-NEXT:     Offset: [[OFFSET]]
+# CHECK-NEXT:     Size: 0x[[#%x,SIZE]]
+# CHECK-NEXT:     Notes [
+# CHECK-NEXT:       {
+# CHECK-NEXT:         Owner: CORE
+# CHECK-NEXT:         Data size: 0x2
+# CHECK-NEXT:         Type: NT_FPREGSET
+# CHECK-NEXT:         Description data (
+# CHECK-NEXT:           0000: 0202
+# CHECK-NEXT:         )
+# CHECK-NEXT:       }
+# CHECK-NEXT:       {
+# CHECK-NEXT:         Owner: CORE
+# CHECK-NEXT:         Data size: 0x2
+# CHECK-NEXT:         Type: NT_TASKSTRUCT
+# CHECK-NEXT:         Description data (
+# CHECK-NEXT:           0000: 0404
+# CHECK-NEXT:         )
+# CHECK-NEXT:       }
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+--- !ELF
+FileHeader:
+  Class:          ELFCLASS64
+  Data:           ELFDATA2LSB
+  Type:           ET_CORE
+  Machine:        EM_X86_64
+ProgramHeaders:
+  - Type:         PT_NOTE
+    MemSize:      0
+    FirstSec:     .note
+    LastSec:      .note
+Sections:
+  - Name:         .note
+    Type:         SHT_NOTE
+    AddressAlign: [[ALIGN]]
+    Notes:
+      - Name:   CORE
+        Type:   0x01
+        Desc:   0101
+      - Name:   CORE
+        Type:   0x02
+        Desc:   0202
+      - Name:   CORE
+        Type:   0x03
+        Desc:   0303
+      - Name:   CORE
+        Type:   0x04
+        Desc:   0404
+      - Name:   LINUX
+        Type:   0x01
+        Desc:   0505
+...
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index 104d802b1e1eeb..5e348d65adca18 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -527,6 +527,37 @@ static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue) {
   return SI;
 }
 
+static Expected<RemoveNoteInfo> parseRemoveNoteInfo(StringRef FlagValue) {
+  // Parse value given with --remove-note option. The format is:
+  //
+  // [name/]type_id
+  //
+  // where:
+  // <name>    - optional note name. If not given, all notes with the specified
+  //             <type_id> are removed.
+  // <type_id> - note type value, can be decimal or hexadecimal number prefixed
+  //             with 0x.
+  RemoveNoteInfo NI;
+  if (FlagValue.empty())
+    return createStringError(errc::invalid_argument,
+                             "bad format for --remove-note, missing type_id");
+  SmallVector<StringRef, 2> Tokens;
+  FlagValue.split(Tokens, '/', /*MaxSplit=*/1);
+  assert(!Tokens.empty() && Tokens.size() <= 2);
+  if (Tokens.size() == 2) {
+    if (Tokens[0].empty())
+      return createStringError(
+          errc::invalid_argument,
+          "bad format for --remove-note, note name is empty");
+    NI.Name = Tokens[0];
+  }
+  if (Tokens.back().getAsInteger(0, NI.TypeId))
+    return createStringError(errc::invalid_argument,
+                             "bad note type_id for --remove-note: '%s'",
+                             Tokens.back().str().c_str());
+  return NI;
+}
+
 // Parse input option \p ArgValue and load section data. This function
 // extracts section name and name of the file keeping section data from
 // ArgValue, loads data from the file, and stores section name and data
@@ -1210,6 +1241,14 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
       };
     }
 
+  for (auto *Arg : InputArgs.filtered(OBJCOPY_remove_note)) {
+    Expected<RemoveNoteInfo> NoteInfo = parseRemoveNoteInfo(Arg->getValue());
+    if (!NoteInfo)
+      return NoteInfo.takeError();
+
+    ELFConfig.NotesToRemove.push_back(*NoteInfo);
+  }
+
   if (Config.DecompressDebugSections &&
       Config.CompressionType != DebugCompressionType::None) {
     return createStringError(
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index 434b5ff92324eb..fbc6a59d9461e7 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -297,3 +297,7 @@ defm pad_to
                    "of zero or the value specified by the --gap-fill option. "
                    "This option is only supported for ELF input and binary output">,
       MetaVarName<"address">;
+
+defm remove_note
+    : Eq<"remove-note", "Remove note(s) with <type_id> and optional <name>">,
+      MetaVarName<"[name/]type_id">;

>From 3550f3afd72092e1664b3c3d46b8f1a5fce7c5a3 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Fri, 13 Dec 2024 22:35:09 -0800
Subject: [PATCH 02/21] fixup: update parsing the argument

---
 llvm/tools/llvm-objcopy/ObjcopyOptions.cpp | 23 +++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index bfd67c558074ef..a5643f0bec5d92 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -549,23 +549,24 @@ static Expected<RemoveNoteInfo> parseRemoveNoteInfo(StringRef FlagValue) {
   // <type_id> - note type value, can be decimal or hexadecimal number prefixed
   //             with 0x.
   RemoveNoteInfo NI;
-  if (FlagValue.empty())
-    return createStringError(errc::invalid_argument,
-                             "bad format for --remove-note, missing type_id");
-  SmallVector<StringRef, 2> Tokens;
-  FlagValue.split(Tokens, '/', /*MaxSplit=*/1);
-  assert(!Tokens.empty() && Tokens.size() <= 2);
-  if (Tokens.size() == 2) {
-    if (Tokens[0].empty())
+  StringRef TypeIdStr;
+  if (auto Idx = FlagValue.find('/'); Idx != StringRef::npos) {
+    if (Idx == 0)
       return createStringError(
           errc::invalid_argument,
           "bad format for --remove-note, note name is empty");
-    NI.Name = Tokens[0];
+    NI.Name = FlagValue.slice(0, Idx);
+    TypeIdStr = FlagValue.substr(Idx + 1);
+  } else {
+    TypeIdStr = FlagValue;
   }
-  if (Tokens.back().getAsInteger(0, NI.TypeId))
+  if (TypeIdStr.empty())
+    return createStringError(errc::invalid_argument,
+                             "bad format for --remove-note, missing type_id");
+  if (TypeIdStr.getAsInteger(0, NI.TypeId))
     return createStringError(errc::invalid_argument,
                              "bad note type_id for --remove-note: '%s'",
-                             Tokens.back().str().c_str());
+                             TypeIdStr.str().c_str());
   return NI;
 }
 

>From 51b05f292ac7475722eedb3f9e1e11040e608dc0 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Fri, 13 Dec 2024 22:35:34 -0800
Subject: [PATCH 03/21] fixup: update tests

---
 llvm/test/tools/llvm-objcopy/ELF/remove-note.test | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
index b24538e26d019e..258ec06fba321e 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
@@ -1,4 +1,5 @@
 # RUN: not llvm-objcopy --remove-note= - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID
+# RUN: not llvm-objcopy --remove-note=CORE/ - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID
 # RUN: not llvm-objcopy --remove-note=/1 - 2>&1 | FileCheck %s --check-prefix=ERR-EMPTYNAME
 # RUN: not llvm-objcopy --remove-note=CORE/1/2 - 2>&1 | FileCheck %s --check-prefix=ERR-INVNUM1
 # RUN: not llvm-objcopy --remove-note=Notanumber - 2>&1 | FileCheck %s --check-prefix=ERR-INVNUM2
@@ -9,15 +10,13 @@
 # ERR-INVNUM1: error: bad note type_id for --remove-note: '1/2'
 # ERR-INVNUM2: error: bad note type_id for --remove-note: 'Notanumber'
 
-# RUN: yaml2obj -D ALIGN=8 %s -o - \
-# RUN:   | llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/0x03 - - \
-# RUN:   | llvm-readobj --segments --sections --notes - \
-# RUN:   | FileCheck %s -D#SIZE=64
+# RUN: yaml2obj -D ALIGN=8 %s -o %t8
+# RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8 %t8o
+# RUN: llvm-readobj --segments --sections --notes %t8o | FileCheck %s -D#SIZE=64
 
-# RUN: yaml2obj -D ALIGN=4 %s -o - \
-# RUN:   | llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/0x03 - - \
-# RUN:   | llvm-readobj --segments --sections --notes - \
-# RUN:   | FileCheck %s -D#SIZE=48
+# RUN: yaml2obj -D ALIGN=4 %s -o %t4
+# RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4 %t4o
+# RUN: llvm-readobj --segments --sections --notes %t4o | FileCheck %s -D#SIZE=48
 
 # CHECK:      Sections [
 # CHECK:        Section {

>From 1bad501c0095b9f4656766f6849848268495a06e Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Fri, 13 Dec 2024 22:48:40 -0800
Subject: [PATCH 04/21] fixup: add the option to the command guide

---
 llvm/docs/CommandGuide/llvm-objcopy.rst | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/llvm/docs/CommandGuide/llvm-objcopy.rst b/llvm/docs/CommandGuide/llvm-objcopy.rst
index e6af47ce9710a6..c57d367261a121 100644
--- a/llvm/docs/CommandGuide/llvm-objcopy.rst
+++ b/llvm/docs/CommandGuide/llvm-objcopy.rst
@@ -464,6 +464,11 @@ them.
 
  Preserve access and modification timestamps in the output.
 
+.. option:: --remove-note [<name>/]<type>
+
+ Remove notes of integer type ``<type>`` and name ``<name>`` from SHT_NOTE
+ sections and PT_NOTE segments. Can be specified multiple times.
+
 .. option:: --rename-section <old>=<new>[,<flag>,...]
 
  Rename sections called ``<old>`` to ``<new>`` in the output, and apply any

>From 3b17fdb705a4ae7ab622bb1c85a13f7821f5570f Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Thu, 19 Dec 2024 18:34:46 -0800
Subject: [PATCH 05/21] fixup: fix updating offsets

---
 llvm/lib/ObjCopy/ELF/ELFObject.cpp            |  9 +++-
 .../tools/llvm-objcopy/ELF/remove-note.test   | 46 ++++++++++++++-----
 2 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index 9f460f685706c8..5f2cef8ac86046 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -2312,6 +2312,11 @@ void Object::updateSegmentData(
     Segment &S, std::vector<uint8_t> NewSegmentData,
     const DenseMap<const SectionBase *, std::pair<uint64_t, uint64_t>>
         &SectionMapping) {
+  // TODO: Update the parent segment
+  assert(!S.ParentSegment);
+  // TODO: Update nested segments
+  assert(!llvm::any_of(
+      Segments, [&S](const SegPtr &Seg) { return Seg->ParentSegment == &S; }));
   auto It =
       UpdatedSegments.insert_or_assign(&S, std::move(NewSegmentData)).first;
   S.Contents = It->second;
@@ -2319,12 +2324,14 @@ void Object::updateSegmentData(
   if (S.MemSize)
     S.MemSize = S.FileSize;
   assert(SectionMapping.size() == S.Sections.size());
+  assert(S.Offset == S.OriginalOffset);
   for (const auto &SM : SectionMapping) {
     assert(SM.first->ParentSegment == &S && S.Sections.count(SM.first));
     assert(SM.second.first >= S.Offset);
     assert((SM.second.first + SM.second.second) <= (S.Offset + S.FileSize));
+    assert(SM.first->Offset == SM.first->OriginalOffset);
     SectionBase *MutSec = const_cast<SectionBase *>(SM.first);
-    MutSec->Offset = SM.second.first;
+    MutSec->OriginalOffset = MutSec->Offset = SM.second.first;
     MutSec->Size = SM.second.second;
   }
 }
diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
index 258ec06fba321e..8475e3f8c31737 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
@@ -12,36 +12,50 @@
 
 # RUN: yaml2obj -D ALIGN=8 %s -o %t8
 # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8 %t8o
-# RUN: llvm-readobj --segments --sections --notes %t8o | FileCheck %s -D#SIZE=64
+# RUN: llvm-readobj --segments --sections --notes %t8o | FileCheck %s -D#SIZE0=32 -D#SIZE1=32
 
 # RUN: yaml2obj -D ALIGN=4 %s -o %t4
 # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4 %t4o
-# RUN: llvm-readobj --segments --sections --notes %t4o | FileCheck %s -D#SIZE=48
+# RUN: llvm-readobj --segments --sections --notes %t4o | FileCheck %s -D#SIZE0=24 -D#SIZE1=24
 
 # CHECK:      Sections [
 # CHECK:        Section {
-# CHECK:          Name: .note
+# CHECK:          Name: .note0
 # CHECK-NEXT:     Type: SHT_NOTE
 # CHECK-NEXT:     Flags [
 # CHECK-NEXT:     ]
 # CHECK-NEXT:     Address:
-# CHECK-NEXT:     Offset: [[OFFSET:0x.+]]
-# CHECK-NEXT:     Size: [[#%d,SIZE]]
+# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0:]]
+# CHECK-NEXT:     Size: [[#%d,SIZE0]]
+# CHECK:          Name: .note1
+# CHECK-NEXT:     Type: SHT_NOTE
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0+SIZE0]]
+# CHECK-NEXT:     Size: [[#%d,SIZE1]]
+# CHECK:          Name: .note2
+# CHECK-NEXT:     Type: SHT_NOTE
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0+SIZE0+SIZE1]]
+# CHECK-NEXT:     Size: 0
 
 # CHECK:      ProgramHeaders [
 # CHECK-NEXT:   ProgramHeader {
 # CHECK-NEXT:     Type: PT_NOTE
-# CHECK-NEXT:     Offset: [[OFFSET]]
+# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0]]
 # CHECK-NEXT:     VirtualAddress: 0x0
 # CHECK-NEXT:     PhysicalAddress: 0x0
-# CHECK-NEXT:     FileSize: [[#%d,SIZE]]
+# CHECK-NEXT:     FileSize: [[#%d,SIZE0+SIZE1]]
 # CHECK-NEXT:     MemSize: 0
 
 # CHECK:      NoteSections [
 # CHECK-NEXT:   NoteSection {
 # CHECK-NEXT:     Name:
-# CHECK-NEXT:     Offset: [[OFFSET]]
-# CHECK-NEXT:     Size: 0x[[#%x,SIZE]]
+# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0]]
+# CHECK-NEXT:     Size: 0x[[#%X,SIZE0+SIZE1]]
 # CHECK-NEXT:     Notes [
 # CHECK-NEXT:       {
 # CHECK-NEXT:         Owner: CORE
@@ -72,10 +86,10 @@ FileHeader:
 ProgramHeaders:
   - Type:         PT_NOTE
     MemSize:      0
-    FirstSec:     .note
-    LastSec:      .note
+    FirstSec:     .note0
+    LastSec:      .note2
 Sections:
-  - Name:         .note
+  - Name:         .note0
     Type:         SHT_NOTE
     AddressAlign: [[ALIGN]]
     Notes:
@@ -85,12 +99,20 @@ Sections:
       - Name:   CORE
         Type:   0x02
         Desc:   0202
+  - Name:         .note1
+    Type:         SHT_NOTE
+    AddressAlign: [[ALIGN]]
+    Notes:
       - Name:   CORE
         Type:   0x03
         Desc:   0303
       - Name:   CORE
         Type:   0x04
         Desc:   0404
+  - Name:         .note2
+    Type:         SHT_NOTE
+    AddressAlign: [[ALIGN]]
+    Notes:
       - Name:   LINUX
         Type:   0x01
         Desc:   0505

>From 1c84760cbce5a9815fc385de58b9e6f0ffccf1ee Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Thu, 19 Dec 2024 19:52:07 -0800
Subject: [PATCH 06/21] fixup: split 'removeNote()'

---
 llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 179 ++++++++++++++++------------
 llvm/lib/ObjCopy/ELF/ELFObject.h    |   8 +-
 2 files changed, 107 insertions(+), 80 deletions(-)

diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index 1df64b0b7ce886..9401310bf27507 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -609,95 +609,122 @@ 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;
+    uint64_t NewPos;
+  };
+
+  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);
+  static Object::Section2OffsetAndSize
+  getSectionMapping(const Segment &Seg, ArrayRef<DeletedRange> ToRemove);
+};
+
+} // namespace
+
 template <class ELFT>
-static Error removeNoteImpl(Object &Obj,
-                            ArrayRef<RemoveNoteInfo> NotesToRemove) {
+std::vector<RemoveNoteDetail::DeletedRange>
+RemoveNoteDetail::findNotesToRemove(ArrayRef<uint8_t> Data, size_t Align,
+                                    ArrayRef<RemoveNoteInfo> NotesToRemove) {
   LLVM_ELF_IMPORT_TYPES_ELFT(ELFT);
-  for (Segment &Seg : Obj.segments()) {
-    // TODO: Support nested segments
-    if (Seg.Type != PT_NOTE || Seg.ParentSegment)
-      continue;
-
-    // Find chunks of the segment data to remove
-    struct DeletedRange {
-      uint64_t OldFrom;
-      uint64_t OldTo;
-      uint64_t NewOffset;
-    };
-    std::vector<DeletedRange> DataToRemove;
-    ArrayRef<uint8_t> OldData = Seg.getContents();
-    size_t Align = std::max<size_t>(4, Seg.Align);
-    uint64_t Offset = 0;
-    while (Offset + sizeof(Elf_Nhdr) <= OldData.size()) {
-      auto Nhdr = reinterpret_cast<const Elf_Nhdr *>(OldData.data() + Offset);
-      size_t FullSize = Nhdr->getSize(Align);
-      if (Offset + FullSize > OldData.size())
-        break;
-      Elf_Note Note(*Nhdr);
-      if (llvm::any_of(NotesToRemove, [&](const RemoveNoteInfo &NoteInfo) {
-            return NoteInfo.TypeId == Note.getType() &&
-                   (NoteInfo.Name.empty() || NoteInfo.Name == Note.getName());
-          }))
-        DataToRemove.push_back({Offset, Offset + FullSize, 0});
-      Offset += FullSize;
-    }
-    if (DataToRemove.empty())
-      continue;
+  std::vector<DeletedRange> ToRemove;
+  uint64_t CurPos = 0;
+  uint64_t NewPos = 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, NewPos});
+    else
+      NewPos += FullSize;
+    CurPos += FullSize;
+  }
+  return ToRemove;
+}
 
-    // Prepare the new segment data
-    std::vector<uint8_t> NewData;
-    NewData.reserve(OldData.size());
-    Offset = 0;
-    for (auto &RemRange : DataToRemove) {
-      if (Offset < RemRange.OldFrom) {
-        auto Slice = OldData.slice(Offset, RemRange.OldFrom - Offset);
-        NewData.insert(NewData.end(), Slice.begin(), Slice.end());
-      }
-      RemRange.NewOffset = NewData.size();
-      Offset = RemRange.OldTo;
-    }
-    if (Offset < OldData.size()) {
-      auto Slice = OldData.slice(Offset);
+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 (auto &RemRange : ToRemove) {
+    if (CurPos < RemRange.OldFrom) {
+      auto Slice = OldData.slice(CurPos, RemRange.OldFrom - CurPos);
       NewData.insert(NewData.end(), Slice.begin(), Slice.end());
     }
+    assert(RemRange.NewPos == NewData.size());
+    CurPos = RemRange.OldTo;
+  }
+  if (CurPos < OldData.size()) {
+    auto Slice = OldData.slice(CurPos);
+    NewData.insert(NewData.end(), Slice.begin(), Slice.end());
+  }
+  return NewData;
+}
 
-    auto CalculateNewOffset = [&](uint64_t SecOffset) {
-      uint64_t Offset = SecOffset - Seg.Offset;
-      auto It =
-          llvm::upper_bound(DataToRemove, Offset,
-                            [](const uint64_t &Off, const DeletedRange &Range) {
-                              return Off < Range.OldFrom;
-                            });
-      if (It != DataToRemove.begin()) {
-        --It;
-        Offset = (Offset > It->OldTo) ? (Offset - It->OldTo + It->NewOffset)
-                                      : It->NewOffset;
-      }
-      return Offset + Seg.Offset;
-    };
-
-    // Remap the segment's sections
-    DenseMap<const SectionBase *, std::pair<uint64_t, uint64_t>> Mapping;
-    for (const SectionBase *Sec : Seg.Sections) {
-      uint64_t NewOffset = CalculateNewOffset(Sec->Offset);
-      uint64_t NewSize =
-          CalculateNewOffset(Sec->Offset + Sec->Size) - NewOffset;
-      Mapping.try_emplace(Sec, NewOffset, NewSize);
+Object::Section2OffsetAndSize
+RemoveNoteDetail::getSectionMapping(const Segment &Seg,
+                                    ArrayRef<DeletedRange> ToRemove) {
+  auto CalculateNewOffset = [&](uint64_t SecOffset) {
+    uint64_t Pos = SecOffset - Seg.Offset;
+    auto It = llvm::upper_bound(
+        ToRemove, Pos, [](const uint64_t &Pos, const DeletedRange &Range) {
+          return Pos < Range.OldFrom;
+        });
+    if (It != ToRemove.begin()) {
+      --It;
+      Pos = (Pos > It->OldTo) ? (Pos - It->OldTo + It->NewPos) : It->NewPos;
     }
+    return Pos + Seg.Offset;
+  };
 
-    Obj.updateSegmentData(Seg, std::move(NewData), Mapping);
+  // Remap the segment's sections
+  Object::Section2OffsetAndSize Mapping;
+  for (const SectionBase *Sec : Seg.Sections) {
+    uint64_t NewOffset = CalculateNewOffset(Sec->Offset);
+    uint64_t NewSize = CalculateNewOffset(Sec->Offset + Sec->Size) - NewOffset;
+    Mapping.try_emplace(Sec, NewOffset, NewSize);
   }
-  return Error::success();
+  return Mapping;
 }
 
 static Error removeNote(Object &Obj, endianness Endianness,
                         ArrayRef<RemoveNoteInfo> NotesToRemove) {
-  // Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the
-  // header, so the parsers are the same.
-  if (Endianness == endianness::little)
-    return removeNoteImpl<ELF64LE>(Obj, NotesToRemove);
-  else
-    return removeNoteImpl<ELF64BE>(Obj, NotesToRemove);
+  for (Segment &Seg : Obj.segments()) {
+    // TODO: Support nested segments
+    if (Seg.Type != PT_NOTE || Seg.ParentSegment)
+      continue;
+    ArrayRef<uint8_t> OldData = Seg.getContents();
+    size_t Align = std::max<size_t>(4, Seg.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())
+      Obj.updateSegmentData(Seg,
+                            RemoveNoteDetail::updateData(OldData, ToRemove),
+                            RemoveNoteDetail::getSectionMapping(Seg, ToRemove));
+  }
+  return Error::success();
 }
 
 static Error
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h
index 5e16d4c0c1885a..fc518327c1be11 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.h
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.h
@@ -1235,10 +1235,10 @@ class Object {
     Segments.emplace_back(std::make_unique<Segment>(Data));
     return *Segments.back();
   }
-  void updateSegmentData(
-      Segment &S, std::vector<uint8_t> NewSegmentData,
-      const DenseMap<const SectionBase *, std::pair<uint64_t, uint64_t>>
-          &SectionMapping);
+  using OffsetAndSize = std::pair<uint64_t, uint64_t>;
+  using Section2OffsetAndSize = DenseMap<const SectionBase *, OffsetAndSize>;
+  void updateSegmentData(Segment &S, std::vector<uint8_t> NewSegmentData,
+                         const Section2OffsetAndSize &SectionMapping);
   bool isRelocatable() const {
     return (Type != ELF::ET_DYN && Type != ELF::ET_EXEC) || MustBeRelocatable;
   }

>From f6d4330cf26dad70e4fb08ff319ffd8c5f057349 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Thu, 19 Dec 2024 20:16:22 -0800
Subject: [PATCH 07/21] fixup: do not allow '--remove-note' with
 '--(remove|add|update)-section'

---
 llvm/test/tools/llvm-objcopy/ELF/remove-note.test | 10 ++++++++++
 llvm/tools/llvm-objcopy/ObjcopyOptions.cpp        | 15 +++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
index 8475e3f8c31737..6eaeda9528a86d 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
@@ -1,3 +1,13 @@
+## Check incompatible options
+# RUN: not llvm-objcopy --remove-note=1 --remove-section=.test - 2>&1 | FileCheck %s --check-prefix=ERR-REMSEC
+# RUN: not llvm-objcopy --remove-note=1 --add-section=.test=%s - 2>&1 | FileCheck %s --check-prefix=ERR-ADDSEC
+# RUN: not llvm-objcopy --remove-note=1 --update-section=.test=%s - 2>&1 | FileCheck %s --check-prefix=ERR-UPDSEC
+
+# ERR-REMSEC: error: cannot specify both --remove-note and --remove-section
+# ERR-ADDSEC: error: cannot specify both --remove-note and --add-section
+# ERR-UPDSEC: error: cannot specify both --remove-note and --update-section
+
+## Check invalid argument formats
 # RUN: not llvm-objcopy --remove-note= - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID
 # RUN: not llvm-objcopy --remove-note=CORE/ - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID
 # RUN: not llvm-objcopy --remove-note=/1 - 2>&1 | FileCheck %s --check-prefix=ERR-EMPTYNAME
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index a5643f0bec5d92..0d209590655ef3 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -1261,6 +1261,21 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
     ELFConfig.NotesToRemove.push_back(*NoteInfo);
   }
 
+  if (!ELFConfig.NotesToRemove.empty()) {
+    if (!Config.ToRemove.empty())
+      return createStringError(
+          errc::invalid_argument,
+          "cannot specify both --remove-note and --remove-section");
+    if (!Config.AddSection.empty())
+      return createStringError(
+          errc::invalid_argument,
+          "cannot specify both --remove-note and --add-section");
+    if (!Config.UpdateSection.empty())
+      return createStringError(
+          errc::invalid_argument,
+          "cannot specify both --remove-note and --update-section");
+  }
+
   if (Config.DecompressDebugSections &&
       Config.CompressionType != DebugCompressionType::None) {
     return createStringError(

>From fd72505eb22a4320463ed01fb54ed15a1c44c24b Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Fri, 20 Dec 2024 19:33:59 -0800
Subject: [PATCH 08/21] fixup: change ELF type of the test file ET_CORE ->
 ET_EXEC

For core files, llvm-readobj dumps note segments as a whole,
without reporting individual sections.
---
 .../tools/llvm-objcopy/ELF/remove-note.test   | 24 +++++++++++++++----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
index 6eaeda9528a86d..768949e2687f07 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
@@ -63,35 +63,49 @@
 
 # CHECK:      NoteSections [
 # CHECK-NEXT:   NoteSection {
-# CHECK-NEXT:     Name:
+# CHECK-NEXT:     Name: .note0
 # CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0]]
-# CHECK-NEXT:     Size: 0x[[#%X,SIZE0+SIZE1]]
+# CHECK-NEXT:     Size: 0x[[#%X,SIZE0]]
 # CHECK-NEXT:     Notes [
 # CHECK-NEXT:       {
 # CHECK-NEXT:         Owner: CORE
 # CHECK-NEXT:         Data size: 0x2
-# CHECK-NEXT:         Type: NT_FPREGSET
+# CHECK-NEXT:         Type: NT_ARCH
 # CHECK-NEXT:         Description data (
 # CHECK-NEXT:           0000: 0202
 # CHECK-NEXT:         )
 # CHECK-NEXT:       }
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
+# CHECK-NEXT:   NoteSection {
+# CHECK-NEXT:     Name: .note1
+# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0+SIZE0]]
+# CHECK-NEXT:     Size: 0x[[#%X,SIZE1]]
+# CHECK-NEXT:     Notes [
 # CHECK-NEXT:       {
 # CHECK-NEXT:         Owner: CORE
 # CHECK-NEXT:         Data size: 0x2
-# CHECK-NEXT:         Type: NT_TASKSTRUCT
+# CHECK-NEXT:         Type: Unknown (0x00000004)
 # CHECK-NEXT:         Description data (
 # CHECK-NEXT:           0000: 0404
 # CHECK-NEXT:         )
 # CHECK-NEXT:       }
 # CHECK-NEXT:     ]
 # CHECK-NEXT:   }
+# CHECK-NEXT:   NoteSection {
+# CHECK-NEXT:     Name: .note2
+# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0+SIZE0+SIZE1]]
+# CHECK-NEXT:     Size: 0x0
+# CHECK-NEXT:     Notes [
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
 # CHECK-NEXT: ]
 
 --- !ELF
 FileHeader:
   Class:          ELFCLASS64
   Data:           ELFDATA2LSB
-  Type:           ET_CORE
+  Type:           ET_EXEC
   Machine:        EM_X86_64
 ProgramHeaders:
   - Type:         PT_NOTE

>From e730cfdaf0ffe463c2692d3dbf98c6da1a0a06bc Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Fri, 20 Dec 2024 19:44:47 -0800
Subject: [PATCH 09/21] fixup: also run the test for ELF32 and BE

---
 .../tools/llvm-objcopy/ELF/remove-note.test   | 23 ++++++++++++-------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
index 768949e2687f07..2053e76593fad1 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
@@ -20,13 +20,20 @@
 # ERR-INVNUM1: error: bad note type_id for --remove-note: '1/2'
 # ERR-INVNUM2: error: bad note type_id for --remove-note: 'Notanumber'
 
-# RUN: yaml2obj -D ALIGN=8 %s -o %t8
-# RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8 %t8o
-# RUN: llvm-readobj --segments --sections --notes %t8o | FileCheck %s -D#SIZE0=32 -D#SIZE1=32
+# RUN: yaml2obj -D ALIGN=8 -D ELFCLASS=64 -D ENDIANNESS=LSB %s -o %t8.64.lsb
+# RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8.64.lsb %t8.64.lsb.o
+# RUN: llvm-readobj --segments --sections --notes %t8.64.lsb.o | \
+# RUN:   FileCheck %s -D#SIZE0=32 -D#SIZE1=32
 
-# RUN: yaml2obj -D ALIGN=4 %s -o %t4
-# RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4 %t4o
-# RUN: llvm-readobj --segments --sections --notes %t4o | FileCheck %s -D#SIZE0=24 -D#SIZE1=24
+# RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=64 -D ENDIANNESS=MSB %s -o %t4.64.msb
+# RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.64.msb %t4.64.msb.o
+# RUN: llvm-readobj --segments --sections --notes %t4.64.msb.o | \
+# RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=24
+
+# RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=32 -D ENDIANNESS=LSB %s -o %t4.32.lsb
+# RUN: llvm-objcopy --remove-note=1 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.32.lsb %t4.32.lsb.o
+# RUN: llvm-readobj --segments --sections --notes %t4.32.lsb.o | \
+# RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=24
 
 # CHECK:      Sections [
 # CHECK:        Section {
@@ -103,8 +110,8 @@
 
 --- !ELF
 FileHeader:
-  Class:          ELFCLASS64
-  Data:           ELFDATA2LSB
+  Class:          ELFCLASS[[ELFCLASS]]
+  Data:           ELFDATA2[[ENDIANNESS]]
   Type:           ET_EXEC
   Machine:        EM_X86_64
 ProgramHeaders:

>From de674542e110dd27a1e42c42301b53aad089efad Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Fri, 20 Dec 2024 19:46:44 -0800
Subject: [PATCH 10/21] fixup: handle SHT_NOTE sections outside of segments

---
 llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp           | 18 ++++++++
 llvm/lib/ObjCopy/ELF/ELFObject.cpp            | 29 +++++++++----
 llvm/lib/ObjCopy/ELF/ELFObject.h              |  8 ++++
 .../tools/llvm-objcopy/ELF/remove-note.test   | 41 +++++++++++++++++--
 4 files changed, 84 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index 9401310bf27507..e7c5cff489d94c 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -724,6 +724,24 @@ static Error removeNote(Object &Obj, endianness Endianness,
                             RemoveNoteDetail::updateData(OldData, ToRemove),
                             RemoveNoteDetail::getSectionMapping(Seg, ToRemove));
   }
+  for (auto &Sec : Obj.sections()) {
+    if (Sec.Type != SHT_NOTE || Sec.ParentSegment || !Sec.hasContents())
+      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();
 }
 
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index 5f2cef8ac86046..8e547fe5529311 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -2154,25 +2154,20 @@ 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());
-
+Error Object::updateSectionData(std::vector<SecPtr>::iterator It,
+                                ArrayRef<uint8_t> Data) {
   auto *OldSec = It->get();
   if (!OldSec->hasContents())
     return createStringError(
         errc::invalid_argument,
         "section '%s' cannot be updated because it does not have contents",
-        Name.str().c_str());
+        OldSec->Name.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 %" PRIu64 " that is part of a segment",
-                             Data.size(), Name.str().c_str(), OldSec->Size);
+                             Data.size(), OldSec->Name.c_str(), OldSec->Size);
 
   if (!OldSec->ParentSegment) {
     *It = std::make_unique<OwnedDataSection>(*OldSec, Data);
@@ -2185,6 +2180,22 @@ Error Object::updateSection(StringRef Name, ArrayRef<uint8_t> 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 fc518327c1be11..285dd0bc12445c 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.h
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.h
@@ -549,6 +549,7 @@ class SectionBase {
   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 @@ class Section : public SectionBase {
   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 @@ class OwnedDataSection : public SectionBase {
   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 {
@@ -1165,6 +1169,9 @@ class Object {
     return Sec.Flags & ELF::SHF_ALLOC;
   };
 
+  Error updateSectionData(std::vector<SecPtr>::iterator SecIt,
+                          ArrayRef<uint8_t> Data);
+
 public:
   template <class T>
   using ConstRange = iterator_range<pointee_iterator<
@@ -1207,6 +1214,7 @@ class Object {
 
   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 =
diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
index 2053e76593fad1..ecb39dba5ab6de 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
@@ -23,17 +23,17 @@
 # RUN: yaml2obj -D ALIGN=8 -D ELFCLASS=64 -D ENDIANNESS=LSB %s -o %t8.64.lsb
 # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8.64.lsb %t8.64.lsb.o
 # RUN: llvm-readobj --segments --sections --notes %t8.64.lsb.o | \
-# RUN:   FileCheck %s -D#SIZE0=32 -D#SIZE1=32
+# RUN:   FileCheck %s -D#SIZE0=32 -D#SIZE1=32 -D#SIZE3=32
 
 # RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=64 -D ENDIANNESS=MSB %s -o %t4.64.msb
 # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.64.msb %t4.64.msb.o
 # RUN: llvm-readobj --segments --sections --notes %t4.64.msb.o | \
-# RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=24
+# RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=24 -D#SIZE3=24
 
 # RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=32 -D ENDIANNESS=LSB %s -o %t4.32.lsb
 # RUN: llvm-objcopy --remove-note=1 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.32.lsb %t4.32.lsb.o
 # RUN: llvm-readobj --segments --sections --notes %t4.32.lsb.o | \
-# RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=24
+# RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=24 -D#SIZE3=24
 
 # CHECK:      Sections [
 # CHECK:        Section {
@@ -58,6 +58,13 @@
 # CHECK-NEXT:     Address:
 # CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0+SIZE0+SIZE1]]
 # CHECK-NEXT:     Size: 0
+# CHECK:          Name: .note3
+# CHECK-NEXT:     Type: SHT_NOTE
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET3:]]
+# CHECK-NEXT:     Size: [[#%d,SIZE3]]
 
 # CHECK:      ProgramHeaders [
 # CHECK-NEXT:   ProgramHeader {
@@ -106,6 +113,21 @@
 # CHECK-NEXT:     Notes [
 # CHECK-NEXT:     ]
 # CHECK-NEXT:   }
+# CHECK-NEXT:   NoteSection {
+# CHECK-NEXT:     Name: .note3
+# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET3]]
+# CHECK-NEXT:     Size: 0x[[#%X,SIZE3]]
+# CHECK-NEXT:     Notes [
+# CHECK-NEXT:       {
+# CHECK-NEXT:         Owner: CORE
+# CHECK-NEXT:         Data size: 0x2
+# CHECK-NEXT:         Type: NT_ARCH
+# CHECK-NEXT:         Description data (
+# CHECK-NEXT:           0000: 0707
+# CHECK-NEXT:         )
+# CHECK-NEXT:       }
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
 # CHECK-NEXT: ]
 
 --- !ELF
@@ -147,4 +169,17 @@ Sections:
       - Name:   LINUX
         Type:   0x01
         Desc:   0505
+  - Name:         .note3
+    Type:         SHT_NOTE
+    AddressAlign: [[ALIGN]]
+    Notes:
+      - Name:   GNU
+        Type:   0x01
+        Desc:   0606
+      - Name:   CORE
+        Type:   0x02
+        Desc:   0707
+      - Name:   CORE
+        Type:   0x03
+        Desc:   0808
 ...

>From 95b6b9407a16f006bf2fbec0452eb10089a45c58 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Mon, 23 Dec 2024 12:50:20 -0800
Subject: [PATCH 11/21] Remove handling for segments

---
 llvm/docs/CommandGuide/llvm-objcopy.rst       |  2 +-
 llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp           | 47 +------------
 llvm/lib/ObjCopy/ELF/ELFObject.cpp            | 28 --------
 llvm/lib/ObjCopy/ELF/ELFObject.h              |  5 --
 .../tools/llvm-objcopy/ELF/remove-note.test   | 70 +++----------------
 5 files changed, 12 insertions(+), 140 deletions(-)

diff --git a/llvm/docs/CommandGuide/llvm-objcopy.rst b/llvm/docs/CommandGuide/llvm-objcopy.rst
index c57d367261a121..166525047d1f54 100644
--- a/llvm/docs/CommandGuide/llvm-objcopy.rst
+++ b/llvm/docs/CommandGuide/llvm-objcopy.rst
@@ -467,7 +467,7 @@ them.
 .. option:: --remove-note [<name>/]<type>
 
  Remove notes of integer type ``<type>`` and name ``<name>`` from SHT_NOTE
- sections and PT_NOTE segments. Can be specified multiple times.
+ sections that are not in a segment. Can be specified multiple times.
 
 .. option:: --rename-section <old>=<new>[,<flag>,...]
 
diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index e7c5cff489d94c..74380bab0e4461 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -623,8 +623,6 @@ struct RemoveNoteDetail {
                     ArrayRef<RemoveNoteInfo> NotesToRemove);
   static std::vector<uint8_t> updateData(ArrayRef<uint8_t> OldData,
                                          ArrayRef<DeletedRange> ToRemove);
-  static Object::Section2OffsetAndSize
-  getSectionMapping(const Segment &Seg, ArrayRef<DeletedRange> ToRemove);
 };
 
 } // namespace
@@ -678,53 +676,10 @@ RemoveNoteDetail::updateData(ArrayRef<uint8_t> OldData,
   return NewData;
 }
 
-Object::Section2OffsetAndSize
-RemoveNoteDetail::getSectionMapping(const Segment &Seg,
-                                    ArrayRef<DeletedRange> ToRemove) {
-  auto CalculateNewOffset = [&](uint64_t SecOffset) {
-    uint64_t Pos = SecOffset - Seg.Offset;
-    auto It = llvm::upper_bound(
-        ToRemove, Pos, [](const uint64_t &Pos, const DeletedRange &Range) {
-          return Pos < Range.OldFrom;
-        });
-    if (It != ToRemove.begin()) {
-      --It;
-      Pos = (Pos > It->OldTo) ? (Pos - It->OldTo + It->NewPos) : It->NewPos;
-    }
-    return Pos + Seg.Offset;
-  };
-
-  // Remap the segment's sections
-  Object::Section2OffsetAndSize Mapping;
-  for (const SectionBase *Sec : Seg.Sections) {
-    uint64_t NewOffset = CalculateNewOffset(Sec->Offset);
-    uint64_t NewSize = CalculateNewOffset(Sec->Offset + Sec->Size) - NewOffset;
-    Mapping.try_emplace(Sec, NewOffset, NewSize);
-  }
-  return Mapping;
-}
-
 static Error removeNote(Object &Obj, endianness Endianness,
                         ArrayRef<RemoveNoteInfo> NotesToRemove) {
-  for (Segment &Seg : Obj.segments()) {
-    // TODO: Support nested segments
-    if (Seg.Type != PT_NOTE || Seg.ParentSegment)
-      continue;
-    ArrayRef<uint8_t> OldData = Seg.getContents();
-    size_t Align = std::max<size_t>(4, Seg.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())
-      Obj.updateSegmentData(Seg,
-                            RemoveNoteDetail::updateData(OldData, ToRemove),
-                            RemoveNoteDetail::getSectionMapping(Seg, ToRemove));
-  }
   for (auto &Sec : Obj.sections()) {
+    // TODO: Support note sections in segments
     if (Sec.Type != SHT_NOTE || Sec.ParentSegment || !Sec.hasContents())
       continue;
     ArrayRef<uint8_t> OldData = Sec.getContents();
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index 8e547fe5529311..2c7a39779220e5 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -2319,34 +2319,6 @@ Error Object::addNewSymbolTable() {
   return Error::success();
 }
 
-void Object::updateSegmentData(
-    Segment &S, std::vector<uint8_t> NewSegmentData,
-    const DenseMap<const SectionBase *, std::pair<uint64_t, uint64_t>>
-        &SectionMapping) {
-  // TODO: Update the parent segment
-  assert(!S.ParentSegment);
-  // TODO: Update nested segments
-  assert(!llvm::any_of(
-      Segments, [&S](const SegPtr &Seg) { return Seg->ParentSegment == &S; }));
-  auto It =
-      UpdatedSegments.insert_or_assign(&S, std::move(NewSegmentData)).first;
-  S.Contents = It->second;
-  S.FileSize = S.Contents.size();
-  if (S.MemSize)
-    S.MemSize = S.FileSize;
-  assert(SectionMapping.size() == S.Sections.size());
-  assert(S.Offset == S.OriginalOffset);
-  for (const auto &SM : SectionMapping) {
-    assert(SM.first->ParentSegment == &S && S.Sections.count(SM.first));
-    assert(SM.second.first >= S.Offset);
-    assert((SM.second.first + SM.second.second) <= (S.Offset + S.FileSize));
-    assert(SM.first->Offset == SM.first->OriginalOffset);
-    SectionBase *MutSec = const_cast<SectionBase *>(SM.first);
-    MutSec->OriginalOffset = MutSec->Offset = SM.second.first;
-    MutSec->Size = SM.second.second;
-  }
-}
-
 // Orders segments such that if x = y->ParentSegment then y comes before x.
 static void orderSegments(std::vector<Segment *> &Segments) {
   llvm::stable_sort(Segments, compareSegmentsByOffset);
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h
index 285dd0bc12445c..8908187673b024 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.h
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.h
@@ -1163,7 +1163,6 @@ class Object {
   std::vector<SegPtr> Segments;
   std::vector<SecPtr> RemovedSections;
   DenseMap<SectionBase *, std::vector<uint8_t>> UpdatedSections;
-  DenseMap<Segment *, std::vector<uint8_t>> UpdatedSegments;
 
   static bool sectionIsAlloc(const SectionBase &Sec) {
     return Sec.Flags & ELF::SHF_ALLOC;
@@ -1243,10 +1242,6 @@ class Object {
     Segments.emplace_back(std::make_unique<Segment>(Data));
     return *Segments.back();
   }
-  using OffsetAndSize = std::pair<uint64_t, uint64_t>;
-  using Section2OffsetAndSize = DenseMap<const SectionBase *, OffsetAndSize>;
-  void updateSegmentData(Segment &S, std::vector<uint8_t> NewSegmentData,
-                         const Section2OffsetAndSize &SectionMapping);
   bool isRelocatable() const {
     return (Type != ELF::ET_DYN && Type != ELF::ET_EXEC) || MustBeRelocatable;
   }
diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
index ecb39dba5ab6de..9ad873066a73e5 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
@@ -23,17 +23,17 @@
 # RUN: yaml2obj -D ALIGN=8 -D ELFCLASS=64 -D ENDIANNESS=LSB %s -o %t8.64.lsb
 # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8.64.lsb %t8.64.lsb.o
 # RUN: llvm-readobj --segments --sections --notes %t8.64.lsb.o | \
-# RUN:   FileCheck %s -D#SIZE0=32 -D#SIZE1=32 -D#SIZE3=32
+# RUN:   FileCheck %s -D#SIZE0=32 -D#SIZE1=32
 
 # RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=64 -D ENDIANNESS=MSB %s -o %t4.64.msb
 # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.64.msb %t4.64.msb.o
 # RUN: llvm-readobj --segments --sections --notes %t4.64.msb.o | \
-# RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=24 -D#SIZE3=24
+# RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=24
 
 # RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=32 -D ENDIANNESS=LSB %s -o %t4.32.lsb
 # RUN: llvm-objcopy --remove-note=1 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.32.lsb %t4.32.lsb.o
 # RUN: llvm-readobj --segments --sections --notes %t4.32.lsb.o | \
-# RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=24 -D#SIZE3=24
+# RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=24
 
 # CHECK:      Sections [
 # CHECK:        Section {
@@ -42,43 +42,27 @@
 # CHECK-NEXT:     Flags [
 # CHECK-NEXT:     ]
 # CHECK-NEXT:     Address:
-# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0:]]
+# CHECK-NEXT:     Offset:
 # CHECK-NEXT:     Size: [[#%d,SIZE0]]
 # CHECK:          Name: .note1
 # CHECK-NEXT:     Type: SHT_NOTE
 # CHECK-NEXT:     Flags [
 # CHECK-NEXT:     ]
 # CHECK-NEXT:     Address:
-# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0+SIZE0]]
+# CHECK-NEXT:     Offset:
 # CHECK-NEXT:     Size: [[#%d,SIZE1]]
 # CHECK:          Name: .note2
 # CHECK-NEXT:     Type: SHT_NOTE
 # CHECK-NEXT:     Flags [
 # CHECK-NEXT:     ]
 # CHECK-NEXT:     Address:
-# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0+SIZE0+SIZE1]]
+# CHECK-NEXT:     Offset:
 # CHECK-NEXT:     Size: 0
-# CHECK:          Name: .note3
-# CHECK-NEXT:     Type: SHT_NOTE
-# CHECK-NEXT:     Flags [
-# CHECK-NEXT:     ]
-# CHECK-NEXT:     Address:
-# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET3:]]
-# CHECK-NEXT:     Size: [[#%d,SIZE3]]
-
-# CHECK:      ProgramHeaders [
-# CHECK-NEXT:   ProgramHeader {
-# CHECK-NEXT:     Type: PT_NOTE
-# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0]]
-# CHECK-NEXT:     VirtualAddress: 0x0
-# CHECK-NEXT:     PhysicalAddress: 0x0
-# CHECK-NEXT:     FileSize: [[#%d,SIZE0+SIZE1]]
-# CHECK-NEXT:     MemSize: 0
 
 # CHECK:      NoteSections [
 # CHECK-NEXT:   NoteSection {
 # CHECK-NEXT:     Name: .note0
-# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0]]
+# CHECK-NEXT:     Offset:
 # CHECK-NEXT:     Size: 0x[[#%X,SIZE0]]
 # CHECK-NEXT:     Notes [
 # CHECK-NEXT:       {
@@ -93,7 +77,7 @@
 # CHECK-NEXT:   }
 # CHECK-NEXT:   NoteSection {
 # CHECK-NEXT:     Name: .note1
-# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0+SIZE0]]
+# CHECK-NEXT:     Offset:
 # CHECK-NEXT:     Size: 0x[[#%X,SIZE1]]
 # CHECK-NEXT:     Notes [
 # CHECK-NEXT:       {
@@ -108,39 +92,18 @@
 # CHECK-NEXT:   }
 # CHECK-NEXT:   NoteSection {
 # CHECK-NEXT:     Name: .note2
-# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET0+SIZE0+SIZE1]]
+# CHECK-NEXT:     Offset:
 # CHECK-NEXT:     Size: 0x0
 # CHECK-NEXT:     Notes [
 # CHECK-NEXT:     ]
 # CHECK-NEXT:   }
-# CHECK-NEXT:   NoteSection {
-# CHECK-NEXT:     Name: .note3
-# CHECK-NEXT:     Offset: 0x[[#%X,OFFSET3]]
-# CHECK-NEXT:     Size: 0x[[#%X,SIZE3]]
-# CHECK-NEXT:     Notes [
-# CHECK-NEXT:       {
-# CHECK-NEXT:         Owner: CORE
-# CHECK-NEXT:         Data size: 0x2
-# CHECK-NEXT:         Type: NT_ARCH
-# CHECK-NEXT:         Description data (
-# CHECK-NEXT:           0000: 0707
-# CHECK-NEXT:         )
-# CHECK-NEXT:       }
-# CHECK-NEXT:     ]
-# CHECK-NEXT:   }
-# CHECK-NEXT: ]
 
 --- !ELF
 FileHeader:
   Class:          ELFCLASS[[ELFCLASS]]
   Data:           ELFDATA2[[ENDIANNESS]]
-  Type:           ET_EXEC
+  Type:           ET_REL
   Machine:        EM_X86_64
-ProgramHeaders:
-  - Type:         PT_NOTE
-    MemSize:      0
-    FirstSec:     .note0
-    LastSec:      .note2
 Sections:
   - Name:         .note0
     Type:         SHT_NOTE
@@ -169,17 +132,4 @@ Sections:
       - Name:   LINUX
         Type:   0x01
         Desc:   0505
-  - Name:         .note3
-    Type:         SHT_NOTE
-    AddressAlign: [[ALIGN]]
-    Notes:
-      - Name:   GNU
-        Type:   0x01
-        Desc:   0606
-      - Name:   CORE
-        Type:   0x02
-        Desc:   0707
-      - Name:   CORE
-        Type:   0x03
-        Desc:   0808
 ...

>From 9baf37aea1d821671e05a96f680a9f43336573fd Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Wed, 15 Jan 2025 22:34:12 -0800
Subject: [PATCH 12/21] Remove DeletedRange.NewPos

---
 llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index 74380bab0e4461..5021c550552038 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -614,7 +614,6 @@ struct RemoveNoteDetail {
   struct DeletedRange {
     uint64_t OldFrom;
     uint64_t OldTo;
-    uint64_t NewPos;
   };
 
   template <class ELFT>
@@ -634,7 +633,6 @@ RemoveNoteDetail::findNotesToRemove(ArrayRef<uint8_t> Data, size_t Align,
   LLVM_ELF_IMPORT_TYPES_ELFT(ELFT);
   std::vector<DeletedRange> ToRemove;
   uint64_t CurPos = 0;
-  uint64_t NewPos = 0;
   while (CurPos + sizeof(Elf_Nhdr) <= Data.size()) {
     auto Nhdr = reinterpret_cast<const Elf_Nhdr *>(Data.data() + CurPos);
     size_t FullSize = Nhdr->getSize(Align);
@@ -647,9 +645,7 @@ RemoveNoteDetail::findNotesToRemove(ArrayRef<uint8_t> Data, size_t Align,
                  (NoteInfo.Name.empty() || NoteInfo.Name == Note.getName());
         });
     if (ShouldRemove)
-      ToRemove.push_back({CurPos, CurPos + FullSize, NewPos});
-    else
-      NewPos += FullSize;
+      ToRemove.push_back({CurPos, CurPos + FullSize});
     CurPos += FullSize;
   }
   return ToRemove;
@@ -666,7 +662,6 @@ RemoveNoteDetail::updateData(ArrayRef<uint8_t> OldData,
       auto Slice = OldData.slice(CurPos, RemRange.OldFrom - CurPos);
       NewData.insert(NewData.end(), Slice.begin(), Slice.end());
     }
-    assert(RemRange.NewPos == NewData.size());
     CurPos = RemRange.OldTo;
   }
   if (CurPos < OldData.size()) {

>From 143246025bc7d593a9a3f9a3d7e58a869e654cd7 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Wed, 15 Jan 2025 22:34:46 -0800
Subject: [PATCH 13/21] "auto &RemRange" -> "const DeletedRange &RemRange"

---
 llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index 5021c550552038..49ecf9b002dc1a 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -657,7 +657,7 @@ RemoveNoteDetail::updateData(ArrayRef<uint8_t> OldData,
   std::vector<uint8_t> NewData;
   NewData.reserve(OldData.size());
   uint64_t CurPos = 0;
-  for (auto &RemRange : ToRemove) {
+  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());

>From a4c8edb634f00f64c8aa7cd30e599c1fa65becca Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Wed, 15 Jan 2025 22:35:42 -0800
Subject: [PATCH 14/21] Remove a blank line at the end of an namespace

---
 llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index 49ecf9b002dc1a..c0a4d0ac8fee7b 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -623,7 +623,6 @@ struct RemoveNoteDetail {
   static std::vector<uint8_t> updateData(ArrayRef<uint8_t> OldData,
                                          ArrayRef<DeletedRange> ToRemove);
 };
-
 } // namespace
 
 template <class ELFT>

>From 56950965c937008b60c17b434f2307e8dc4e78c6 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Thu, 16 Jan 2025 13:52:47 -0800
Subject: [PATCH 15/21] Print a warning for note segments and note sections in
 segments

---
 llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h    | 22 +++++---
 .../include/llvm/ObjCopy/MachO/MachOObjcopy.h | 10 +++-
 llvm/include/llvm/ObjCopy/ObjCopy.h           | 12 +++-
 llvm/lib/ObjCopy/Archive.cpp                  | 13 +++--
 llvm/lib/ObjCopy/Archive.h                    |  4 +-
 llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp           | 55 ++++++++++++-------
 llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp       | 17 +++---
 llvm/lib/ObjCopy/ObjCopy.cpp                  | 11 ++--
 .../ELF/remove-note-unsupported.test          | 47 ++++++++++++++++
 llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp  | 22 +++++---
 llvm/tools/llvm-objcopy/llvm-objcopy.cpp      | 13 +++--
 llvm/unittests/ObjCopy/ObjCopyTest.cpp        |  3 +-
 12 files changed, 165 insertions(+), 64 deletions(-)
 create mode 100644 llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test

diff --git a/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h b/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h
index 552b6fb655f186..2254bb3826cf5a 100644
--- a/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h
+++ b/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h
@@ -9,10 +9,13 @@
 #ifndef LLVM_OBJCOPY_ELF_ELFOBJCOPY_H
 #define LLVM_OBJCOPY_ELF_ELFOBJCOPY_H
 
+#include "llvm/ADT/STLFunctionalExtras.h"
+
 namespace llvm {
 class Error;
 class MemoryBuffer;
 class raw_ostream;
+class Twine;
 
 namespace object {
 class ELFObjectFileBase;
@@ -25,26 +28,29 @@ struct ELFConfig;
 namespace elf {
 /// Apply the transformations described by \p Config and \p ELFConfig to
 /// \p In, which must represent an IHex file, and writes the result
-/// into \p Out.
+/// into \p Out. Warnings can be printed via \p WarningCallback.
 /// \returns any Error encountered whilst performing the operation.
 Error executeObjcopyOnIHex(const CommonConfig &Config,
                            const ELFConfig &ELFConfig, MemoryBuffer &In,
-                           raw_ostream &Out);
+                           raw_ostream &Out,
+                           function_ref<void(const Twine &)> WarningCallback);
 
 /// Apply the transformations described by \p Config and \p ELFConfig to
 /// \p In, which is treated as a raw binary input, and writes the result
-/// into \p Out.
+/// into \p Out. Warnings can be printed via \p WarningCallback.
 /// \returns any Error encountered whilst performing the operation.
-Error executeObjcopyOnRawBinary(const CommonConfig &Config,
-                                const ELFConfig &ELFConfig, MemoryBuffer &In,
-                                raw_ostream &Out);
+Error executeObjcopyOnRawBinary(
+    const CommonConfig &Config, const ELFConfig &ELFConfig, MemoryBuffer &In,
+    raw_ostream &Out, function_ref<void(const Twine &)> WarningCallback);
 
 /// Apply the transformations described by \p Config and \p ELFConfig to
-/// \p In and writes the result into \p Out.
+/// \p In and writes the result into \p Out. Warnings can be printed via
+/// \p WarningCallback.
 /// \returns any Error encountered whilst performing the operation.
 Error executeObjcopyOnBinary(const CommonConfig &Config,
                              const ELFConfig &ELFConfig,
-                             object::ELFObjectFileBase &In, raw_ostream &Out);
+                             object::ELFObjectFileBase &In, raw_ostream &Out,
+                             function_ref<void(const Twine &)> WarningCallback);
 
 } // end namespace elf
 } // end namespace objcopy
diff --git a/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h b/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h
index 73690d7ace8a51..7dbb7b0a2f5afc 100644
--- a/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h
+++ b/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h
@@ -9,9 +9,12 @@
 #ifndef LLVM_OBJCOPY_MACHO_MACHOOBJCOPY_H
 #define LLVM_OBJCOPY_MACHO_MACHOOBJCOPY_H
 
+#include "llvm/ADT/STLFunctionalExtras.h"
+
 namespace llvm {
 class Error;
 class raw_ostream;
+class Twine;
 
 namespace object {
 class MachOObjectFile;
@@ -26,17 +29,20 @@ class MultiFormatConfig;
 namespace macho {
 /// Apply the transformations described by \p Config and \p MachOConfig to
 /// \p In and writes the result into \p Out.
+/// Warnings can be printed via \p WarningCallback.
 /// \returns any Error encountered whilst performing the operation.
 Error executeObjcopyOnBinary(const CommonConfig &Config,
                              const MachOConfig &MachOConfig,
-                             object::MachOObjectFile &In, raw_ostream &Out);
+                             object::MachOObjectFile &In, raw_ostream &Out,
+                             function_ref<void(const Twine &)> WarningCallback);
 
 /// Apply the transformations described by \p Config and \p MachOConfig to
 /// \p In and writes the result into \p Out.
+/// Warnings can be printed via \p WarningCallback.
 /// \returns any Error encountered whilst performing the operation.
 Error executeObjcopyOnMachOUniversalBinary(
     const MultiFormatConfig &Config, const object::MachOUniversalBinary &In,
-    raw_ostream &Out);
+    raw_ostream &Out, function_ref<void(const Twine &)> WarningCallback);
 
 } // end namespace macho
 } // end namespace objcopy
diff --git a/llvm/include/llvm/ObjCopy/ObjCopy.h b/llvm/include/llvm/ObjCopy/ObjCopy.h
index 023814002c7271..76ba4949bf04c7 100644
--- a/llvm/include/llvm/ObjCopy/ObjCopy.h
+++ b/llvm/include/llvm/ObjCopy/ObjCopy.h
@@ -9,10 +9,12 @@
 #ifndef LLVM_OBJCOPY_OBJCOPY_H
 #define LLVM_OBJCOPY_OBJCOPY_H
 
+#include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/Support/Error.h"
 
 namespace llvm {
 class raw_ostream;
+class Twine;
 
 namespace object {
 class Archive;
@@ -25,16 +27,20 @@ class MultiFormatConfig;
 /// Applies the transformations described by \p Config to
 /// each member in archive \p Ar.
 /// Writes a result in a file specified by \p Config.OutputFilename.
+/// Warnings can be printed via \p WarningCallback.
 /// \returns any Error encountered whilst performing the operation.
-Error executeObjcopyOnArchive(const MultiFormatConfig &Config,
-                              const object::Archive &Ar);
+Error executeObjcopyOnArchive(
+    const MultiFormatConfig &Config, const object::Archive &Ar,
+    function_ref<void(const Twine &)> WarningCallback);
 
 /// Applies the transformations described by \p Config to \p In and writes
 /// the result into \p Out. This function does the dispatch based on the
 /// format of the input binary (COFF, ELF, MachO or wasm).
+/// Warnings can be printed via \p WarningCallback.
 /// \returns any Error encountered whilst performing the operation.
 Error executeObjcopyOnBinary(const MultiFormatConfig &Config,
-                             object::Binary &In, raw_ostream &Out);
+                             object::Binary &In, raw_ostream &Out,
+                             function_ref<void(const Twine &)> WarningCallback);
 
 } // end namespace objcopy
 } // end namespace llvm
diff --git a/llvm/lib/ObjCopy/Archive.cpp b/llvm/lib/ObjCopy/Archive.cpp
index a221c64edf06bd..5e3882c45a0f24 100644
--- a/llvm/lib/ObjCopy/Archive.cpp
+++ b/llvm/lib/ObjCopy/Archive.cpp
@@ -20,7 +20,8 @@ namespace objcopy {
 using namespace llvm::object;
 
 Expected<std::vector<NewArchiveMember>>
-createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar) {
+createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar,
+                        function_ref<void(const Twine &)> WarningCallback) {
   std::vector<NewArchiveMember> NewArchiveMembers;
   Error Err = Error::success();
   for (const Archive::Child &Child : Ar.children(Err)) {
@@ -36,7 +37,8 @@ createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar) {
     SmallVector<char, 0> Buffer;
     raw_svector_ostream MemStream(Buffer);
 
-    if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream))
+    if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream,
+                                         WarningCallback))
       return std::move(E);
 
     Expected<NewArchiveMember> Member = NewArchiveMember::getOldMember(
@@ -94,10 +96,11 @@ static Error deepWriteArchive(StringRef ArcName,
   return Error::success();
 }
 
-Error executeObjcopyOnArchive(const MultiFormatConfig &Config,
-                              const object::Archive &Ar) {
+Error executeObjcopyOnArchive(
+    const MultiFormatConfig &Config, const object::Archive &Ar,
+    function_ref<void(const Twine &)> WarningCallback) {
   Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr =
-      createNewArchiveMembers(Config, Ar);
+      createNewArchiveMembers(Config, Ar, WarningCallback);
   if (!NewArchiveMembersOrErr)
     return NewArchiveMembersOrErr.takeError();
   const CommonConfig &CommonConfig = Config.getCommonConfig();
diff --git a/llvm/lib/ObjCopy/Archive.h b/llvm/lib/ObjCopy/Archive.h
index 08aae563505ce7..d9094ed0f4f531 100644
--- a/llvm/lib/ObjCopy/Archive.h
+++ b/llvm/lib/ObjCopy/Archive.h
@@ -20,10 +20,12 @@ class MultiFormatConfig;
 
 /// Applies the transformations described by \p Config to
 /// each member in archive \p Ar.
+/// Warnings can be printed via \p WarningCallback.
 /// \returns Vector of transformed archive members.
 Expected<std::vector<NewArchiveMember>>
 createNewArchiveMembers(const MultiFormatConfig &Config,
-                        const object::Archive &Ar);
+                        const object::Archive &Ar,
+                        function_ref<void(const Twine &)> WarningCallback);
 
 } // end namespace objcopy
 } // end namespace llvm
diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index c0a4d0ac8fee7b..9643c14bcfdb18 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -671,11 +671,24 @@ RemoveNoteDetail::updateData(ArrayRef<uint8_t> OldData,
 }
 
 static Error removeNote(Object &Obj, endianness Endianness,
-                        ArrayRef<RemoveNoteInfo> NotesToRemove) {
+                        ArrayRef<RemoveNoteInfo> NotesToRemove,
+                        function_ref<void(const Twine &)> WarningCallback) {
+  // TODO: Support note segments.
+  for (Segment &Seg : Obj.segments()) {
+    if (Seg.Type == PT_NOTE) {
+      WarningCallback("note segments are not supported");
+      break;
+    }
+  }
   for (auto &Sec : Obj.sections()) {
-    // TODO: Support note sections in segments
-    if (Sec.Type != SHT_NOTE || Sec.ParentSegment || !Sec.hasContents())
+    if (Sec.Type != SHT_NOTE || !Sec.hasContents())
       continue;
+    // TODO: Support note sections in segments.
+    if (Sec.ParentSegment) {
+      WarningCallback("cannot remove note(s) from " + Sec.Name +
+                      ": sections in segments are not supported");
+      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
@@ -759,7 +772,8 @@ static Error verifyNoteSection(StringRef Name, endianness Endianness,
 // depend a) on the order the options occur in or b) on some opaque priority
 // system. The only priority is that keeps/copies overrule removes.
 static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
-                        ElfType OutputElfType, Object &Obj) {
+                        ElfType OutputElfType, Object &Obj,
+                        function_ref<void(const Twine &)> WarningCallback) {
   if (Config.OutputArch) {
     Obj.Machine = Config.OutputArch->EMachine;
     Obj.OSABI = Config.OutputArch->OSABI;
@@ -885,7 +899,8 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
                      : endianness::big;
 
   if (!ELFConfig.NotesToRemove.empty()) {
-    if (Error Err = removeNote(Obj, E, ELFConfig.NotesToRemove))
+    if (Error Err =
+            removeNote(Obj, E, ELFConfig.NotesToRemove, WarningCallback))
       return Err;
   }
 
@@ -1020,9 +1035,9 @@ static Error writeOutput(const CommonConfig &Config, Object &Obj,
   return Writer->write();
 }
 
-Error objcopy::elf::executeObjcopyOnIHex(const CommonConfig &Config,
-                                         const ELFConfig &ELFConfig,
-                                         MemoryBuffer &In, raw_ostream &Out) {
+Error objcopy::elf::executeObjcopyOnIHex(
+    const CommonConfig &Config, const ELFConfig &ELFConfig, MemoryBuffer &In,
+    raw_ostream &Out, function_ref<void(const Twine &)> WarningCallback) {
   IHexReader Reader(&In);
   Expected<std::unique_ptr<Object>> Obj = Reader.create(true);
   if (!Obj)
@@ -1030,15 +1045,15 @@ Error objcopy::elf::executeObjcopyOnIHex(const CommonConfig &Config,
 
   const ElfType OutputElfType =
       getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
-  if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
+  if (Error E =
+          handleArgs(Config, ELFConfig, OutputElfType, **Obj, WarningCallback))
     return E;
   return writeOutput(Config, **Obj, Out, OutputElfType);
 }
 
-Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config,
-                                              const ELFConfig &ELFConfig,
-                                              MemoryBuffer &In,
-                                              raw_ostream &Out) {
+Error objcopy::elf::executeObjcopyOnRawBinary(
+    const CommonConfig &Config, const ELFConfig &ELFConfig, MemoryBuffer &In,
+    raw_ostream &Out, function_ref<void(const Twine &)> WarningCallback) {
   BinaryReader Reader(&In, ELFConfig.NewSymbolVisibility);
   Expected<std::unique_ptr<Object>> Obj = Reader.create(true);
   if (!Obj)
@@ -1048,15 +1063,16 @@ Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config,
   // (-B<arch>).
   const ElfType OutputElfType =
       getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
-  if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
+  if (Error E =
+          handleArgs(Config, ELFConfig, OutputElfType, **Obj, WarningCallback))
     return E;
   return writeOutput(Config, **Obj, Out, OutputElfType);
 }
 
-Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config,
-                                           const ELFConfig &ELFConfig,
-                                           object::ELFObjectFileBase &In,
-                                           raw_ostream &Out) {
+Error objcopy::elf::executeObjcopyOnBinary(
+    const CommonConfig &Config, const ELFConfig &ELFConfig,
+    object::ELFObjectFileBase &In, raw_ostream &Out,
+    function_ref<void(const Twine &)> WarningCallback) {
   ELFReader Reader(&In, Config.ExtractPartition);
   Expected<std::unique_ptr<Object>> Obj =
       Reader.create(!Config.SymbolsToAdd.empty());
@@ -1067,7 +1083,8 @@ Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config,
                                     ? getOutputElfType(*Config.OutputArch)
                                     : getOutputElfType(In);
 
-  if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
+  if (Error E =
+          handleArgs(Config, ELFConfig, OutputElfType, **Obj, WarningCallback))
     return createFileError(Config.InputFilename, std::move(E));
 
   if (Error E = writeOutput(Config, **Obj, Out, OutputElfType))
diff --git a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp
index 91500c2d9dd47d..e98a40ff3cc0e0 100644
--- a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp
+++ b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp
@@ -445,10 +445,10 @@ static Error handleArgs(const CommonConfig &Config,
   return Error::success();
 }
 
-Error objcopy::macho::executeObjcopyOnBinary(const CommonConfig &Config,
-                                             const MachOConfig &MachOConfig,
-                                             object::MachOObjectFile &In,
-                                             raw_ostream &Out) {
+Error objcopy::macho::executeObjcopyOnBinary(
+    const CommonConfig &Config, const MachOConfig &MachOConfig,
+    object::MachOObjectFile &In, raw_ostream &Out,
+    function_ref<void(const Twine &)> WarningCallback) {
   MachOReader Reader(In);
   Expected<std::unique_ptr<Object>> O = Reader.create();
   if (!O)
@@ -484,14 +484,14 @@ Error objcopy::macho::executeObjcopyOnBinary(const CommonConfig &Config,
 
 Error objcopy::macho::executeObjcopyOnMachOUniversalBinary(
     const MultiFormatConfig &Config, const MachOUniversalBinary &In,
-    raw_ostream &Out) {
+    raw_ostream &Out, function_ref<void(const Twine &)> WarningCallback) {
   SmallVector<OwningBinary<Binary>, 2> Binaries;
   SmallVector<Slice, 2> Slices;
   for (const auto &O : In.objects()) {
     Expected<std::unique_ptr<Archive>> ArOrErr = O.getAsArchive();
     if (ArOrErr) {
       Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr =
-          createNewArchiveMembers(Config, **ArOrErr);
+          createNewArchiveMembers(Config, **ArOrErr, WarningCallback);
       if (!NewArchiveMembersOrErr)
         return NewArchiveMembersOrErr.takeError();
       auto Kind = (*ArOrErr)->kind();
@@ -542,8 +542,9 @@ Error objcopy::macho::executeObjcopyOnMachOUniversalBinary(
     if (!MachO)
       return MachO.takeError();
 
-    if (Error E = executeObjcopyOnBinary(Config.getCommonConfig(), *MachO,
-                                         **ObjOrErr, MemStream))
+    if (Error E =
+            executeObjcopyOnBinary(Config.getCommonConfig(), *MachO, **ObjOrErr,
+                                   MemStream, WarningCallback))
       return E;
 
     auto MB = std::make_unique<SmallVectorMemoryBuffer>(
diff --git a/llvm/lib/ObjCopy/ObjCopy.cpp b/llvm/lib/ObjCopy/ObjCopy.cpp
index 54dab11c4b1921..3f8716e4fecd94 100644
--- a/llvm/lib/ObjCopy/ObjCopy.cpp
+++ b/llvm/lib/ObjCopy/ObjCopy.cpp
@@ -33,15 +33,16 @@ using namespace llvm::object;
 
 /// The function executeObjcopyOnBinary does the dispatch based on the format
 /// of the input binary (ELF, MachO or COFF).
-Error executeObjcopyOnBinary(const MultiFormatConfig &Config,
-                             object::Binary &In, raw_ostream &Out) {
+Error executeObjcopyOnBinary(
+    const MultiFormatConfig &Config, object::Binary &In, raw_ostream &Out,
+    function_ref<void(const Twine &)> WarningCallback) {
   if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In)) {
     Expected<const ELFConfig &> ELFConfig = Config.getELFConfig();
     if (!ELFConfig)
       return ELFConfig.takeError();
 
     return elf::executeObjcopyOnBinary(Config.getCommonConfig(), *ELFConfig,
-                                       *ELFBinary, Out);
+                                       *ELFBinary, Out, WarningCallback);
   }
   if (auto *COFFBinary = dyn_cast<object::COFFObjectFile>(&In)) {
     Expected<const COFFConfig &> COFFConfig = Config.getCOFFConfig();
@@ -57,12 +58,12 @@ Error executeObjcopyOnBinary(const MultiFormatConfig &Config,
       return MachOConfig.takeError();
 
     return macho::executeObjcopyOnBinary(Config.getCommonConfig(), *MachOConfig,
-                                         *MachOBinary, Out);
+                                         *MachOBinary, Out, WarningCallback);
   }
   if (auto *MachOUniversalBinary =
           dyn_cast<object::MachOUniversalBinary>(&In)) {
     return macho::executeObjcopyOnMachOUniversalBinary(
-        Config, *MachOUniversalBinary, Out);
+        Config, *MachOUniversalBinary, Out, WarningCallback);
   }
   if (auto *WasmBinary = dyn_cast<object::WasmObjectFile>(&In)) {
     Expected<const WasmConfig &> WasmConfig = Config.getWasmConfig();
diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test
new file mode 100644
index 00000000000000..e664328d7aecf6
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test
@@ -0,0 +1,47 @@
+# RUN: yaml2obj --docnum=1 %s -o %t1
+# RUN: llvm-objcopy --remove-note=1 %t1 %t1o 2>&1 | FileCheck %s --check-prefix=NOTE_SEGMENT
+# NOTE_SEGMENT: warning: note segments are not supported
+# NOTE_SEGMENT-NOT: note segments are not supported
+
+--- !ELF
+FileHeader:
+  Class:          ELFCLASS64
+  Data:           ELFDATA2LSB
+  Type:           ET_EXEC
+  Machine:        EM_X86_64
+ProgramHeaders:
+  - Type:         PT_NOTE
+    FirstSec:     .data0
+    LastSec:      .data0
+  - Type:         PT_NOTE
+    FirstSec:     .data1
+    LastSec:      .data1
+Sections:
+  - Name:         .data0
+    Type:         SHT_PROGBITS
+    AddressAlign: 4
+    Content:      "1122334455"
+  - Name:         .data1
+    Type:         SHT_PROGBITS
+    AddressAlign: 4
+    Content:      "1122334455"
+
+# RUN: yaml2obj --docnum=2 %s -o %t2
+# RUN: llvm-objcopy --remove-note=1 %t2 %t2o 2>&1 | FileCheck %s --check-prefix=NOTE_SECTION
+# NOTE_SECTION: warning: cannot remove note(s) from .note: sections in segments are not supported
+
+--- !ELF
+FileHeader:
+  Class:          ELFCLASS64
+  Data:           ELFDATA2LSB
+  Type:           ET_EXEC
+  Machine:        EM_X86_64
+ProgramHeaders:
+  - Type:         PT_LOAD
+    FirstSec:     .note
+    LastSec:      .note
+Sections:
+  - Name:         .note
+    Type:         SHT_NOTE
+    AddressAlign: 4
+    Content:      "1122334455"
diff --git a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
index 0180abb834f9d3..1c9b70f457f0d7 100644
--- a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
+++ b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
@@ -65,6 +65,10 @@ namespace dwarfutil {
 
 std::string ToolName;
 
+static void reportWarningMsg(const Twine &Msg) {
+  WithColor::warning(errs(), ToolName) << Msg << '\n';
+}
+
 static mc::RegisterMCTargetOptionsFlags MOF;
 
 static Error validateAndSetOptions(opt::InputArgList &Args, Options &Options) {
@@ -261,8 +265,8 @@ static Expected<uint32_t> saveSeparateDebugInfo(const Options &Opts,
   if (Error Err = writeToOutput(
           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
             raw_crc_ostream CRCBuffer(OutFile);
-            if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile,
-                                                            CRCBuffer))
+            if (Error Err = objcopy::executeObjcopyOnBinary(
+                    Config, InputFile, CRCBuffer, reportWarningMsg))
               return Err;
 
             WrittenFileCRC32 = CRCBuffer.getCRC32();
@@ -285,8 +289,8 @@ static Error saveNonDebugInfo(const Options &Opts, ObjectFile &InputFile,
 
   if (Error Err = writeToOutput(
           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
-            if (Error Err =
-                    objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile))
+            if (Error Err = objcopy::executeObjcopyOnBinary(
+                    Config, InputFile, OutFile, reportWarningMsg))
               return Err;
 
             return Error::success();
@@ -373,8 +377,8 @@ saveSeparateLinkedDebugInfo(const Options &Opts, ObjectFile &InputFile,
           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
             raw_crc_ostream CRCBuffer(OutFile);
 
-            if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile,
-                                                            CRCBuffer))
+            if (Error Err = objcopy::executeObjcopyOnBinary(
+                    Config, InputFile, CRCBuffer, reportWarningMsg))
               return Err;
 
             WrittenFileCRC32 = CRCBuffer.getCRC32();
@@ -399,7 +403,8 @@ static Error saveSingleLinkedDebugInfo(const Options &Opts,
 
   if (Error Err = writeToOutput(
           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
-            return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile);
+            return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile,
+                                                   reportWarningMsg);
           }))
     return Err;
 
@@ -435,7 +440,8 @@ static Error saveCopyOfFile(const Options &Opts, ObjectFile &InputFile) {
 
   if (Error Err = writeToOutput(
           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
-            return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile);
+            return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile,
+                                                   reportWarningMsg);
           }))
     return Err;
 
diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
index ad3e60472369bf..71f3f2233ae072 100644
--- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -71,6 +71,10 @@ static ErrorSuccess reportWarning(Error E) {
   return Error::success();
 }
 
+static void reportWarningMsg(const Twine &Msg) {
+  WithColor::warning(errs(), ToolName) << Msg << '\n';
+}
+
 static Expected<DriverConfig> getDriverConfig(ArrayRef<const char *> Args) {
   StringRef Stem = sys::path::stem(ToolName);
   auto Is = [=](StringRef Tool) {
@@ -105,7 +109,7 @@ static Error executeObjcopyOnIHex(ConfigManager &ConfigMgr, MemoryBuffer &In,
     return ELFConfig.takeError();
 
   return elf::executeObjcopyOnIHex(ConfigMgr.getCommonConfig(), *ELFConfig, In,
-                                   Out);
+                                   Out, reportWarningMsg);
 }
 
 /// The function executeObjcopyOnRawBinary does the dispatch based on the format
@@ -126,7 +130,8 @@ static Error executeObjcopyOnRawBinary(ConfigManager &ConfigMgr,
     if (!ELFConfig)
       return ELFConfig.takeError();
 
-    return elf::executeObjcopyOnRawBinary(Config, *ELFConfig, In, Out);
+    return elf::executeObjcopyOnRawBinary(Config, *ELFConfig, In, Out,
+                                          reportWarningMsg);
   }
 
   llvm_unreachable("unsupported output format");
@@ -176,13 +181,13 @@ static Error executeObjcopy(ConfigManager &ConfigMgr) {
 
     if (Archive *Ar = dyn_cast<Archive>(BinaryHolder.getBinary())) {
       // Handle Archive.
-      if (Error E = executeObjcopyOnArchive(ConfigMgr, *Ar))
+      if (Error E = executeObjcopyOnArchive(ConfigMgr, *Ar, reportWarningMsg))
         return E;
     } else {
       // Handle llvm::object::Binary.
       ObjcopyFunc = [&](raw_ostream &OutFile) -> Error {
         return executeObjcopyOnBinary(ConfigMgr, *BinaryHolder.getBinary(),
-                                      OutFile);
+                                      OutFile, reportWarningMsg);
       };
     }
   }
diff --git a/llvm/unittests/ObjCopy/ObjCopyTest.cpp b/llvm/unittests/ObjCopy/ObjCopyTest.cpp
index 4382c73e889e99..244280047a8cc8 100644
--- a/llvm/unittests/ObjCopy/ObjCopyTest.cpp
+++ b/llvm/unittests/ObjCopy/ObjCopyTest.cpp
@@ -125,7 +125,8 @@ callObjCopy(ConfigManager &Config, object::Binary &In,
             function_ref<bool(const Binary &File)> IsValidFormat) {
   raw_svector_ostream OutStream(DataVector);
 
-  if (Error Err = objcopy::executeObjcopyOnBinary(Config, In, OutStream))
+  if (Error Err = objcopy::executeObjcopyOnBinary(Config, In, OutStream,
+                                                  [](const Twine &) {}))
     return std::move(Err);
 
   MemoryBufferRef Buffer(StringRef(DataVector.data(), DataVector.size()),

>From 17a3c7719412924caabad3b4ce4cf9f8699ef087 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Thu, 16 Jan 2025 18:16:52 -0800
Subject: [PATCH 16/21] Extend the test

---
 .../tools/llvm-objcopy/ELF/remove-note.test   | 37 +++++++++++++------
 1 file changed, 26 insertions(+), 11 deletions(-)

diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
index 9ad873066a73e5..06762892e0de5e 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
@@ -1,4 +1,4 @@
-## Check incompatible options
+## Check incompatible options.
 # RUN: not llvm-objcopy --remove-note=1 --remove-section=.test - 2>&1 | FileCheck %s --check-prefix=ERR-REMSEC
 # RUN: not llvm-objcopy --remove-note=1 --add-section=.test=%s - 2>&1 | FileCheck %s --check-prefix=ERR-ADDSEC
 # RUN: not llvm-objcopy --remove-note=1 --update-section=.test=%s - 2>&1 | FileCheck %s --check-prefix=ERR-UPDSEC
@@ -7,7 +7,7 @@
 # ERR-ADDSEC: error: cannot specify both --remove-note and --add-section
 # ERR-UPDSEC: error: cannot specify both --remove-note and --update-section
 
-## Check invalid argument formats
+## Check invalid argument formats.
 # RUN: not llvm-objcopy --remove-note= - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID
 # RUN: not llvm-objcopy --remove-note=CORE/ - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID
 # RUN: not llvm-objcopy --remove-note=/1 - 2>&1 | FileCheck %s --check-prefix=ERR-EMPTYNAME
@@ -20,20 +20,24 @@
 # ERR-INVNUM1: error: bad note type_id for --remove-note: '1/2'
 # ERR-INVNUM2: error: bad note type_id for --remove-note: 'Notanumber'
 
+## Check deleting notes:
+## * --remove-note=1 will remove note "CORE/1" and "LINUX/1",
+## * --remove-note=DUMMY/2 will not remove any notes because there are no notes with this owner,
+## * --remove-note=CORE/3 will remove "CORE/3" but preserve "LINUX/3".
 # RUN: yaml2obj -D ALIGN=8 -D ELFCLASS=64 -D ENDIANNESS=LSB %s -o %t8.64.lsb
 # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8.64.lsb %t8.64.lsb.o
 # RUN: llvm-readobj --segments --sections --notes %t8.64.lsb.o | \
-# RUN:   FileCheck %s -D#SIZE0=32 -D#SIZE1=32
+# RUN:   FileCheck %s -D#SIZE0=32 -D#SIZE1=64
 
 # RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=64 -D ENDIANNESS=MSB %s -o %t4.64.msb
 # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.64.msb %t4.64.msb.o
 # RUN: llvm-readobj --segments --sections --notes %t4.64.msb.o | \
-# RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=24
+# RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=48
 
 # RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=32 -D ENDIANNESS=LSB %s -o %t4.32.lsb
 # RUN: llvm-objcopy --remove-note=1 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.32.lsb %t4.32.lsb.o
 # RUN: llvm-readobj --segments --sections --notes %t4.32.lsb.o | \
-# RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=24
+# RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=48
 
 # CHECK:      Sections [
 # CHECK:        Section {
@@ -70,7 +74,7 @@
 # CHECK-NEXT:         Data size: 0x2
 # CHECK-NEXT:         Type: NT_ARCH
 # CHECK-NEXT:         Description data (
-# CHECK-NEXT:           0000: 0202
+# CHECK-NEXT:           0000: 0201
 # CHECK-NEXT:         )
 # CHECK-NEXT:       }
 # CHECK-NEXT:     ]
@@ -81,11 +85,19 @@
 # CHECK-NEXT:     Size: 0x[[#%X,SIZE1]]
 # CHECK-NEXT:     Notes [
 # CHECK-NEXT:       {
+# CHECK-NEXT:         Owner: LINUX
+# CHECK-NEXT:         Data size: 0x2
+# CHECK-NEXT:         Type: Unknown (0x00000003)
+# CHECK-NEXT:         Description data (
+# CHECK-NEXT:           0000: 0301
+# CHECK-NEXT:         )
+# CHECK-NEXT:       }
+# CHECK-NEXT:       {
 # CHECK-NEXT:         Owner: CORE
 # CHECK-NEXT:         Data size: 0x2
 # CHECK-NEXT:         Type: Unknown (0x00000004)
 # CHECK-NEXT:         Description data (
-# CHECK-NEXT:           0000: 0404
+# CHECK-NEXT:           0000: 0401
 # CHECK-NEXT:         )
 # CHECK-NEXT:       }
 # CHECK-NEXT:     ]
@@ -114,22 +126,25 @@ Sections:
         Desc:   0101
       - Name:   CORE
         Type:   0x02
-        Desc:   0202
+        Desc:   0201
   - Name:         .note1
     Type:         SHT_NOTE
     AddressAlign: [[ALIGN]]
     Notes:
+      - Name:   LINUX
+        Type:   0x03
+        Desc:   0301
       - Name:   CORE
         Type:   0x03
-        Desc:   0303
+        Desc:   0302
       - Name:   CORE
         Type:   0x04
-        Desc:   0404
+        Desc:   0401
   - Name:         .note2
     Type:         SHT_NOTE
     AddressAlign: [[ALIGN]]
     Notes:
       - Name:   LINUX
         Type:   0x01
-        Desc:   0505
+        Desc:   0102
 ...

>From 08f7f2378ca2d3578ea287b6774e3037ebbcd4c6 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Fri, 17 Jan 2025 17:01:30 -0800
Subject: [PATCH 17/21] Revert "Print a warning for note segments and note
 sections in segments"

This reverts commit 56950965c937008b60c17b434f2307e8dc4e78c6.
---
 llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h    | 22 +++-----
 .../include/llvm/ObjCopy/MachO/MachOObjcopy.h | 10 +---
 llvm/include/llvm/ObjCopy/ObjCopy.h           | 12 +---
 llvm/lib/ObjCopy/Archive.cpp                  | 13 ++---
 llvm/lib/ObjCopy/Archive.h                    |  4 +-
 llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp           | 55 +++++++------------
 llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp       | 17 +++---
 llvm/lib/ObjCopy/ObjCopy.cpp                  | 11 ++--
 .../ELF/remove-note-unsupported.test          | 47 ----------------
 llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp  | 22 +++-----
 llvm/tools/llvm-objcopy/llvm-objcopy.cpp      | 13 ++---
 llvm/unittests/ObjCopy/ObjCopyTest.cpp        |  3 +-
 12 files changed, 64 insertions(+), 165 deletions(-)
 delete mode 100644 llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test

diff --git a/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h b/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h
index 2254bb3826cf5a..552b6fb655f186 100644
--- a/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h
+++ b/llvm/include/llvm/ObjCopy/ELF/ELFObjcopy.h
@@ -9,13 +9,10 @@
 #ifndef LLVM_OBJCOPY_ELF_ELFOBJCOPY_H
 #define LLVM_OBJCOPY_ELF_ELFOBJCOPY_H
 
-#include "llvm/ADT/STLFunctionalExtras.h"
-
 namespace llvm {
 class Error;
 class MemoryBuffer;
 class raw_ostream;
-class Twine;
 
 namespace object {
 class ELFObjectFileBase;
@@ -28,29 +25,26 @@ struct ELFConfig;
 namespace elf {
 /// Apply the transformations described by \p Config and \p ELFConfig to
 /// \p In, which must represent an IHex file, and writes the result
-/// into \p Out. Warnings can be printed via \p WarningCallback.
+/// into \p Out.
 /// \returns any Error encountered whilst performing the operation.
 Error executeObjcopyOnIHex(const CommonConfig &Config,
                            const ELFConfig &ELFConfig, MemoryBuffer &In,
-                           raw_ostream &Out,
-                           function_ref<void(const Twine &)> WarningCallback);
+                           raw_ostream &Out);
 
 /// Apply the transformations described by \p Config and \p ELFConfig to
 /// \p In, which is treated as a raw binary input, and writes the result
-/// into \p Out. Warnings can be printed via \p WarningCallback.
+/// into \p Out.
 /// \returns any Error encountered whilst performing the operation.
-Error executeObjcopyOnRawBinary(
-    const CommonConfig &Config, const ELFConfig &ELFConfig, MemoryBuffer &In,
-    raw_ostream &Out, function_ref<void(const Twine &)> WarningCallback);
+Error executeObjcopyOnRawBinary(const CommonConfig &Config,
+                                const ELFConfig &ELFConfig, MemoryBuffer &In,
+                                raw_ostream &Out);
 
 /// Apply the transformations described by \p Config and \p ELFConfig to
-/// \p In and writes the result into \p Out. Warnings can be printed via
-/// \p WarningCallback.
+/// \p In and writes the result into \p Out.
 /// \returns any Error encountered whilst performing the operation.
 Error executeObjcopyOnBinary(const CommonConfig &Config,
                              const ELFConfig &ELFConfig,
-                             object::ELFObjectFileBase &In, raw_ostream &Out,
-                             function_ref<void(const Twine &)> WarningCallback);
+                             object::ELFObjectFileBase &In, raw_ostream &Out);
 
 } // end namespace elf
 } // end namespace objcopy
diff --git a/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h b/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h
index 7dbb7b0a2f5afc..73690d7ace8a51 100644
--- a/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h
+++ b/llvm/include/llvm/ObjCopy/MachO/MachOObjcopy.h
@@ -9,12 +9,9 @@
 #ifndef LLVM_OBJCOPY_MACHO_MACHOOBJCOPY_H
 #define LLVM_OBJCOPY_MACHO_MACHOOBJCOPY_H
 
-#include "llvm/ADT/STLFunctionalExtras.h"
-
 namespace llvm {
 class Error;
 class raw_ostream;
-class Twine;
 
 namespace object {
 class MachOObjectFile;
@@ -29,20 +26,17 @@ class MultiFormatConfig;
 namespace macho {
 /// Apply the transformations described by \p Config and \p MachOConfig to
 /// \p In and writes the result into \p Out.
-/// Warnings can be printed via \p WarningCallback.
 /// \returns any Error encountered whilst performing the operation.
 Error executeObjcopyOnBinary(const CommonConfig &Config,
                              const MachOConfig &MachOConfig,
-                             object::MachOObjectFile &In, raw_ostream &Out,
-                             function_ref<void(const Twine &)> WarningCallback);
+                             object::MachOObjectFile &In, raw_ostream &Out);
 
 /// Apply the transformations described by \p Config and \p MachOConfig to
 /// \p In and writes the result into \p Out.
-/// Warnings can be printed via \p WarningCallback.
 /// \returns any Error encountered whilst performing the operation.
 Error executeObjcopyOnMachOUniversalBinary(
     const MultiFormatConfig &Config, const object::MachOUniversalBinary &In,
-    raw_ostream &Out, function_ref<void(const Twine &)> WarningCallback);
+    raw_ostream &Out);
 
 } // end namespace macho
 } // end namespace objcopy
diff --git a/llvm/include/llvm/ObjCopy/ObjCopy.h b/llvm/include/llvm/ObjCopy/ObjCopy.h
index 76ba4949bf04c7..023814002c7271 100644
--- a/llvm/include/llvm/ObjCopy/ObjCopy.h
+++ b/llvm/include/llvm/ObjCopy/ObjCopy.h
@@ -9,12 +9,10 @@
 #ifndef LLVM_OBJCOPY_OBJCOPY_H
 #define LLVM_OBJCOPY_OBJCOPY_H
 
-#include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/Support/Error.h"
 
 namespace llvm {
 class raw_ostream;
-class Twine;
 
 namespace object {
 class Archive;
@@ -27,20 +25,16 @@ class MultiFormatConfig;
 /// Applies the transformations described by \p Config to
 /// each member in archive \p Ar.
 /// Writes a result in a file specified by \p Config.OutputFilename.
-/// Warnings can be printed via \p WarningCallback.
 /// \returns any Error encountered whilst performing the operation.
-Error executeObjcopyOnArchive(
-    const MultiFormatConfig &Config, const object::Archive &Ar,
-    function_ref<void(const Twine &)> WarningCallback);
+Error executeObjcopyOnArchive(const MultiFormatConfig &Config,
+                              const object::Archive &Ar);
 
 /// Applies the transformations described by \p Config to \p In and writes
 /// the result into \p Out. This function does the dispatch based on the
 /// format of the input binary (COFF, ELF, MachO or wasm).
-/// Warnings can be printed via \p WarningCallback.
 /// \returns any Error encountered whilst performing the operation.
 Error executeObjcopyOnBinary(const MultiFormatConfig &Config,
-                             object::Binary &In, raw_ostream &Out,
-                             function_ref<void(const Twine &)> WarningCallback);
+                             object::Binary &In, raw_ostream &Out);
 
 } // end namespace objcopy
 } // end namespace llvm
diff --git a/llvm/lib/ObjCopy/Archive.cpp b/llvm/lib/ObjCopy/Archive.cpp
index 5e3882c45a0f24..a221c64edf06bd 100644
--- a/llvm/lib/ObjCopy/Archive.cpp
+++ b/llvm/lib/ObjCopy/Archive.cpp
@@ -20,8 +20,7 @@ namespace objcopy {
 using namespace llvm::object;
 
 Expected<std::vector<NewArchiveMember>>
-createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar,
-                        function_ref<void(const Twine &)> WarningCallback) {
+createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar) {
   std::vector<NewArchiveMember> NewArchiveMembers;
   Error Err = Error::success();
   for (const Archive::Child &Child : Ar.children(Err)) {
@@ -37,8 +36,7 @@ createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar,
     SmallVector<char, 0> Buffer;
     raw_svector_ostream MemStream(Buffer);
 
-    if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream,
-                                         WarningCallback))
+    if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream))
       return std::move(E);
 
     Expected<NewArchiveMember> Member = NewArchiveMember::getOldMember(
@@ -96,11 +94,10 @@ static Error deepWriteArchive(StringRef ArcName,
   return Error::success();
 }
 
-Error executeObjcopyOnArchive(
-    const MultiFormatConfig &Config, const object::Archive &Ar,
-    function_ref<void(const Twine &)> WarningCallback) {
+Error executeObjcopyOnArchive(const MultiFormatConfig &Config,
+                              const object::Archive &Ar) {
   Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr =
-      createNewArchiveMembers(Config, Ar, WarningCallback);
+      createNewArchiveMembers(Config, Ar);
   if (!NewArchiveMembersOrErr)
     return NewArchiveMembersOrErr.takeError();
   const CommonConfig &CommonConfig = Config.getCommonConfig();
diff --git a/llvm/lib/ObjCopy/Archive.h b/llvm/lib/ObjCopy/Archive.h
index d9094ed0f4f531..08aae563505ce7 100644
--- a/llvm/lib/ObjCopy/Archive.h
+++ b/llvm/lib/ObjCopy/Archive.h
@@ -20,12 +20,10 @@ class MultiFormatConfig;
 
 /// Applies the transformations described by \p Config to
 /// each member in archive \p Ar.
-/// Warnings can be printed via \p WarningCallback.
 /// \returns Vector of transformed archive members.
 Expected<std::vector<NewArchiveMember>>
 createNewArchiveMembers(const MultiFormatConfig &Config,
-                        const object::Archive &Ar,
-                        function_ref<void(const Twine &)> WarningCallback);
+                        const object::Archive &Ar);
 
 } // end namespace objcopy
 } // end namespace llvm
diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index 9643c14bcfdb18..c0a4d0ac8fee7b 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -671,24 +671,11 @@ RemoveNoteDetail::updateData(ArrayRef<uint8_t> OldData,
 }
 
 static Error removeNote(Object &Obj, endianness Endianness,
-                        ArrayRef<RemoveNoteInfo> NotesToRemove,
-                        function_ref<void(const Twine &)> WarningCallback) {
-  // TODO: Support note segments.
-  for (Segment &Seg : Obj.segments()) {
-    if (Seg.Type == PT_NOTE) {
-      WarningCallback("note segments are not supported");
-      break;
-    }
-  }
+                        ArrayRef<RemoveNoteInfo> NotesToRemove) {
   for (auto &Sec : Obj.sections()) {
-    if (Sec.Type != SHT_NOTE || !Sec.hasContents())
+    // TODO: Support note sections in segments
+    if (Sec.Type != SHT_NOTE || Sec.ParentSegment || !Sec.hasContents())
       continue;
-    // TODO: Support note sections in segments.
-    if (Sec.ParentSegment) {
-      WarningCallback("cannot remove note(s) from " + Sec.Name +
-                      ": sections in segments are not supported");
-      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
@@ -772,8 +759,7 @@ static Error verifyNoteSection(StringRef Name, endianness Endianness,
 // depend a) on the order the options occur in or b) on some opaque priority
 // system. The only priority is that keeps/copies overrule removes.
 static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
-                        ElfType OutputElfType, Object &Obj,
-                        function_ref<void(const Twine &)> WarningCallback) {
+                        ElfType OutputElfType, Object &Obj) {
   if (Config.OutputArch) {
     Obj.Machine = Config.OutputArch->EMachine;
     Obj.OSABI = Config.OutputArch->OSABI;
@@ -899,8 +885,7 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
                      : endianness::big;
 
   if (!ELFConfig.NotesToRemove.empty()) {
-    if (Error Err =
-            removeNote(Obj, E, ELFConfig.NotesToRemove, WarningCallback))
+    if (Error Err = removeNote(Obj, E, ELFConfig.NotesToRemove))
       return Err;
   }
 
@@ -1035,9 +1020,9 @@ static Error writeOutput(const CommonConfig &Config, Object &Obj,
   return Writer->write();
 }
 
-Error objcopy::elf::executeObjcopyOnIHex(
-    const CommonConfig &Config, const ELFConfig &ELFConfig, MemoryBuffer &In,
-    raw_ostream &Out, function_ref<void(const Twine &)> WarningCallback) {
+Error objcopy::elf::executeObjcopyOnIHex(const CommonConfig &Config,
+                                         const ELFConfig &ELFConfig,
+                                         MemoryBuffer &In, raw_ostream &Out) {
   IHexReader Reader(&In);
   Expected<std::unique_ptr<Object>> Obj = Reader.create(true);
   if (!Obj)
@@ -1045,15 +1030,15 @@ Error objcopy::elf::executeObjcopyOnIHex(
 
   const ElfType OutputElfType =
       getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
-  if (Error E =
-          handleArgs(Config, ELFConfig, OutputElfType, **Obj, WarningCallback))
+  if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
     return E;
   return writeOutput(Config, **Obj, Out, OutputElfType);
 }
 
-Error objcopy::elf::executeObjcopyOnRawBinary(
-    const CommonConfig &Config, const ELFConfig &ELFConfig, MemoryBuffer &In,
-    raw_ostream &Out, function_ref<void(const Twine &)> WarningCallback) {
+Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config,
+                                              const ELFConfig &ELFConfig,
+                                              MemoryBuffer &In,
+                                              raw_ostream &Out) {
   BinaryReader Reader(&In, ELFConfig.NewSymbolVisibility);
   Expected<std::unique_ptr<Object>> Obj = Reader.create(true);
   if (!Obj)
@@ -1063,16 +1048,15 @@ Error objcopy::elf::executeObjcopyOnRawBinary(
   // (-B<arch>).
   const ElfType OutputElfType =
       getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
-  if (Error E =
-          handleArgs(Config, ELFConfig, OutputElfType, **Obj, WarningCallback))
+  if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
     return E;
   return writeOutput(Config, **Obj, Out, OutputElfType);
 }
 
-Error objcopy::elf::executeObjcopyOnBinary(
-    const CommonConfig &Config, const ELFConfig &ELFConfig,
-    object::ELFObjectFileBase &In, raw_ostream &Out,
-    function_ref<void(const Twine &)> WarningCallback) {
+Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config,
+                                           const ELFConfig &ELFConfig,
+                                           object::ELFObjectFileBase &In,
+                                           raw_ostream &Out) {
   ELFReader Reader(&In, Config.ExtractPartition);
   Expected<std::unique_ptr<Object>> Obj =
       Reader.create(!Config.SymbolsToAdd.empty());
@@ -1083,8 +1067,7 @@ Error objcopy::elf::executeObjcopyOnBinary(
                                     ? getOutputElfType(*Config.OutputArch)
                                     : getOutputElfType(In);
 
-  if (Error E =
-          handleArgs(Config, ELFConfig, OutputElfType, **Obj, WarningCallback))
+  if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
     return createFileError(Config.InputFilename, std::move(E));
 
   if (Error E = writeOutput(Config, **Obj, Out, OutputElfType))
diff --git a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp
index e98a40ff3cc0e0..91500c2d9dd47d 100644
--- a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp
+++ b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp
@@ -445,10 +445,10 @@ static Error handleArgs(const CommonConfig &Config,
   return Error::success();
 }
 
-Error objcopy::macho::executeObjcopyOnBinary(
-    const CommonConfig &Config, const MachOConfig &MachOConfig,
-    object::MachOObjectFile &In, raw_ostream &Out,
-    function_ref<void(const Twine &)> WarningCallback) {
+Error objcopy::macho::executeObjcopyOnBinary(const CommonConfig &Config,
+                                             const MachOConfig &MachOConfig,
+                                             object::MachOObjectFile &In,
+                                             raw_ostream &Out) {
   MachOReader Reader(In);
   Expected<std::unique_ptr<Object>> O = Reader.create();
   if (!O)
@@ -484,14 +484,14 @@ Error objcopy::macho::executeObjcopyOnBinary(
 
 Error objcopy::macho::executeObjcopyOnMachOUniversalBinary(
     const MultiFormatConfig &Config, const MachOUniversalBinary &In,
-    raw_ostream &Out, function_ref<void(const Twine &)> WarningCallback) {
+    raw_ostream &Out) {
   SmallVector<OwningBinary<Binary>, 2> Binaries;
   SmallVector<Slice, 2> Slices;
   for (const auto &O : In.objects()) {
     Expected<std::unique_ptr<Archive>> ArOrErr = O.getAsArchive();
     if (ArOrErr) {
       Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr =
-          createNewArchiveMembers(Config, **ArOrErr, WarningCallback);
+          createNewArchiveMembers(Config, **ArOrErr);
       if (!NewArchiveMembersOrErr)
         return NewArchiveMembersOrErr.takeError();
       auto Kind = (*ArOrErr)->kind();
@@ -542,9 +542,8 @@ Error objcopy::macho::executeObjcopyOnMachOUniversalBinary(
     if (!MachO)
       return MachO.takeError();
 
-    if (Error E =
-            executeObjcopyOnBinary(Config.getCommonConfig(), *MachO, **ObjOrErr,
-                                   MemStream, WarningCallback))
+    if (Error E = executeObjcopyOnBinary(Config.getCommonConfig(), *MachO,
+                                         **ObjOrErr, MemStream))
       return E;
 
     auto MB = std::make_unique<SmallVectorMemoryBuffer>(
diff --git a/llvm/lib/ObjCopy/ObjCopy.cpp b/llvm/lib/ObjCopy/ObjCopy.cpp
index 3f8716e4fecd94..54dab11c4b1921 100644
--- a/llvm/lib/ObjCopy/ObjCopy.cpp
+++ b/llvm/lib/ObjCopy/ObjCopy.cpp
@@ -33,16 +33,15 @@ using namespace llvm::object;
 
 /// The function executeObjcopyOnBinary does the dispatch based on the format
 /// of the input binary (ELF, MachO or COFF).
-Error executeObjcopyOnBinary(
-    const MultiFormatConfig &Config, object::Binary &In, raw_ostream &Out,
-    function_ref<void(const Twine &)> WarningCallback) {
+Error executeObjcopyOnBinary(const MultiFormatConfig &Config,
+                             object::Binary &In, raw_ostream &Out) {
   if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In)) {
     Expected<const ELFConfig &> ELFConfig = Config.getELFConfig();
     if (!ELFConfig)
       return ELFConfig.takeError();
 
     return elf::executeObjcopyOnBinary(Config.getCommonConfig(), *ELFConfig,
-                                       *ELFBinary, Out, WarningCallback);
+                                       *ELFBinary, Out);
   }
   if (auto *COFFBinary = dyn_cast<object::COFFObjectFile>(&In)) {
     Expected<const COFFConfig &> COFFConfig = Config.getCOFFConfig();
@@ -58,12 +57,12 @@ Error executeObjcopyOnBinary(
       return MachOConfig.takeError();
 
     return macho::executeObjcopyOnBinary(Config.getCommonConfig(), *MachOConfig,
-                                         *MachOBinary, Out, WarningCallback);
+                                         *MachOBinary, Out);
   }
   if (auto *MachOUniversalBinary =
           dyn_cast<object::MachOUniversalBinary>(&In)) {
     return macho::executeObjcopyOnMachOUniversalBinary(
-        Config, *MachOUniversalBinary, Out, WarningCallback);
+        Config, *MachOUniversalBinary, Out);
   }
   if (auto *WasmBinary = dyn_cast<object::WasmObjectFile>(&In)) {
     Expected<const WasmConfig &> WasmConfig = Config.getWasmConfig();
diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test
deleted file mode 100644
index e664328d7aecf6..00000000000000
--- a/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test
+++ /dev/null
@@ -1,47 +0,0 @@
-# RUN: yaml2obj --docnum=1 %s -o %t1
-# RUN: llvm-objcopy --remove-note=1 %t1 %t1o 2>&1 | FileCheck %s --check-prefix=NOTE_SEGMENT
-# NOTE_SEGMENT: warning: note segments are not supported
-# NOTE_SEGMENT-NOT: note segments are not supported
-
---- !ELF
-FileHeader:
-  Class:          ELFCLASS64
-  Data:           ELFDATA2LSB
-  Type:           ET_EXEC
-  Machine:        EM_X86_64
-ProgramHeaders:
-  - Type:         PT_NOTE
-    FirstSec:     .data0
-    LastSec:      .data0
-  - Type:         PT_NOTE
-    FirstSec:     .data1
-    LastSec:      .data1
-Sections:
-  - Name:         .data0
-    Type:         SHT_PROGBITS
-    AddressAlign: 4
-    Content:      "1122334455"
-  - Name:         .data1
-    Type:         SHT_PROGBITS
-    AddressAlign: 4
-    Content:      "1122334455"
-
-# RUN: yaml2obj --docnum=2 %s -o %t2
-# RUN: llvm-objcopy --remove-note=1 %t2 %t2o 2>&1 | FileCheck %s --check-prefix=NOTE_SECTION
-# NOTE_SECTION: warning: cannot remove note(s) from .note: sections in segments are not supported
-
---- !ELF
-FileHeader:
-  Class:          ELFCLASS64
-  Data:           ELFDATA2LSB
-  Type:           ET_EXEC
-  Machine:        EM_X86_64
-ProgramHeaders:
-  - Type:         PT_LOAD
-    FirstSec:     .note
-    LastSec:      .note
-Sections:
-  - Name:         .note
-    Type:         SHT_NOTE
-    AddressAlign: 4
-    Content:      "1122334455"
diff --git a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
index 1c9b70f457f0d7..0180abb834f9d3 100644
--- a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
+++ b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
@@ -65,10 +65,6 @@ namespace dwarfutil {
 
 std::string ToolName;
 
-static void reportWarningMsg(const Twine &Msg) {
-  WithColor::warning(errs(), ToolName) << Msg << '\n';
-}
-
 static mc::RegisterMCTargetOptionsFlags MOF;
 
 static Error validateAndSetOptions(opt::InputArgList &Args, Options &Options) {
@@ -265,8 +261,8 @@ static Expected<uint32_t> saveSeparateDebugInfo(const Options &Opts,
   if (Error Err = writeToOutput(
           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
             raw_crc_ostream CRCBuffer(OutFile);
-            if (Error Err = objcopy::executeObjcopyOnBinary(
-                    Config, InputFile, CRCBuffer, reportWarningMsg))
+            if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile,
+                                                            CRCBuffer))
               return Err;
 
             WrittenFileCRC32 = CRCBuffer.getCRC32();
@@ -289,8 +285,8 @@ static Error saveNonDebugInfo(const Options &Opts, ObjectFile &InputFile,
 
   if (Error Err = writeToOutput(
           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
-            if (Error Err = objcopy::executeObjcopyOnBinary(
-                    Config, InputFile, OutFile, reportWarningMsg))
+            if (Error Err =
+                    objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile))
               return Err;
 
             return Error::success();
@@ -377,8 +373,8 @@ saveSeparateLinkedDebugInfo(const Options &Opts, ObjectFile &InputFile,
           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
             raw_crc_ostream CRCBuffer(OutFile);
 
-            if (Error Err = objcopy::executeObjcopyOnBinary(
-                    Config, InputFile, CRCBuffer, reportWarningMsg))
+            if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile,
+                                                            CRCBuffer))
               return Err;
 
             WrittenFileCRC32 = CRCBuffer.getCRC32();
@@ -403,8 +399,7 @@ static Error saveSingleLinkedDebugInfo(const Options &Opts,
 
   if (Error Err = writeToOutput(
           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
-            return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile,
-                                                   reportWarningMsg);
+            return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile);
           }))
     return Err;
 
@@ -440,8 +435,7 @@ static Error saveCopyOfFile(const Options &Opts, ObjectFile &InputFile) {
 
   if (Error Err = writeToOutput(
           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
-            return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile,
-                                                   reportWarningMsg);
+            return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile);
           }))
     return Err;
 
diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
index 71f3f2233ae072..ad3e60472369bf 100644
--- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -71,10 +71,6 @@ static ErrorSuccess reportWarning(Error E) {
   return Error::success();
 }
 
-static void reportWarningMsg(const Twine &Msg) {
-  WithColor::warning(errs(), ToolName) << Msg << '\n';
-}
-
 static Expected<DriverConfig> getDriverConfig(ArrayRef<const char *> Args) {
   StringRef Stem = sys::path::stem(ToolName);
   auto Is = [=](StringRef Tool) {
@@ -109,7 +105,7 @@ static Error executeObjcopyOnIHex(ConfigManager &ConfigMgr, MemoryBuffer &In,
     return ELFConfig.takeError();
 
   return elf::executeObjcopyOnIHex(ConfigMgr.getCommonConfig(), *ELFConfig, In,
-                                   Out, reportWarningMsg);
+                                   Out);
 }
 
 /// The function executeObjcopyOnRawBinary does the dispatch based on the format
@@ -130,8 +126,7 @@ static Error executeObjcopyOnRawBinary(ConfigManager &ConfigMgr,
     if (!ELFConfig)
       return ELFConfig.takeError();
 
-    return elf::executeObjcopyOnRawBinary(Config, *ELFConfig, In, Out,
-                                          reportWarningMsg);
+    return elf::executeObjcopyOnRawBinary(Config, *ELFConfig, In, Out);
   }
 
   llvm_unreachable("unsupported output format");
@@ -181,13 +176,13 @@ static Error executeObjcopy(ConfigManager &ConfigMgr) {
 
     if (Archive *Ar = dyn_cast<Archive>(BinaryHolder.getBinary())) {
       // Handle Archive.
-      if (Error E = executeObjcopyOnArchive(ConfigMgr, *Ar, reportWarningMsg))
+      if (Error E = executeObjcopyOnArchive(ConfigMgr, *Ar))
         return E;
     } else {
       // Handle llvm::object::Binary.
       ObjcopyFunc = [&](raw_ostream &OutFile) -> Error {
         return executeObjcopyOnBinary(ConfigMgr, *BinaryHolder.getBinary(),
-                                      OutFile, reportWarningMsg);
+                                      OutFile);
       };
     }
   }
diff --git a/llvm/unittests/ObjCopy/ObjCopyTest.cpp b/llvm/unittests/ObjCopy/ObjCopyTest.cpp
index 244280047a8cc8..4382c73e889e99 100644
--- a/llvm/unittests/ObjCopy/ObjCopyTest.cpp
+++ b/llvm/unittests/ObjCopy/ObjCopyTest.cpp
@@ -125,8 +125,7 @@ callObjCopy(ConfigManager &Config, object::Binary &In,
             function_ref<bool(const Binary &File)> IsValidFormat) {
   raw_svector_ostream OutStream(DataVector);
 
-  if (Error Err = objcopy::executeObjcopyOnBinary(Config, In, OutStream,
-                                                  [](const Twine &) {}))
+  if (Error Err = objcopy::executeObjcopyOnBinary(Config, In, OutStream))
     return std::move(Err);
 
   MemoryBufferRef Buffer(StringRef(DataVector.data(), DataVector.size()),

>From 1ee4850bbb6d35c9327e4bc0eb5c5a17a2b69422 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Fri, 17 Jan 2025 17:02:13 -0800
Subject: [PATCH 18/21] removeNote() -> removeNotes()

---
 llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index c0a4d0ac8fee7b..7c6e957c86e47e 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -670,8 +670,8 @@ RemoveNoteDetail::updateData(ArrayRef<uint8_t> OldData,
   return NewData;
 }
 
-static Error removeNote(Object &Obj, endianness Endianness,
-                        ArrayRef<RemoveNoteInfo> NotesToRemove) {
+static Error removeNotes(Object &Obj, endianness Endianness,
+                         ArrayRef<RemoveNoteInfo> NotesToRemove) {
   for (auto &Sec : Obj.sections()) {
     // TODO: Support note sections in segments
     if (Sec.Type != SHT_NOTE || Sec.ParentSegment || !Sec.hasContents())
@@ -885,7 +885,7 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
                      : endianness::big;
 
   if (!ELFConfig.NotesToRemove.empty()) {
-    if (Error Err = removeNote(Obj, E, ELFConfig.NotesToRemove))
+    if (Error Err = removeNotes(Obj, E, ELFConfig.NotesToRemove))
       return Err;
   }
 

>From 2860c31aac25dd5afdb2fde14574e3eebde22a75 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Fri, 17 Jan 2025 20:13:19 -0800
Subject: [PATCH 19/21] Print a warning for note segments and note sections in
 segments v2

---
 llvm/include/llvm/ObjCopy/CommonConfig.h      |  5 ++
 llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp           | 30 ++++++++++--
 .../ELF/remove-note-unsupported.test          | 47 +++++++++++++++++++
 llvm/tools/llvm-objcopy/llvm-objcopy.cpp      |  2 +
 4 files changed, 80 insertions(+), 4 deletions(-)
 create mode 100644 llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test

diff --git a/llvm/include/llvm/ObjCopy/CommonConfig.h b/llvm/include/llvm/ObjCopy/CommonConfig.h
index 5ae09760e9a542..aea9cd6f9a9c72 100644
--- a/llvm/include/llvm/ObjCopy/CommonConfig.h
+++ b/llvm/include/llvm/ObjCopy/CommonConfig.h
@@ -281,6 +281,11 @@ struct CommonConfig {
 
   SmallVector<std::pair<NameMatcher, llvm::DebugCompressionType>, 0>
       compressSections;
+
+  // ErrorCallback is used to handle recoverable errors. An Error returned
+  // by the callback aborts the execution and is then returned to the caller.
+  // If the callback is not set, the errors are not issued.
+  std::function<Error(Error)> ErrorCallback;
 };
 
 } // namespace objcopy
diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index 7c6e957c86e47e..42581af387d8db 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -671,11 +671,32 @@ RemoveNoteDetail::updateData(ArrayRef<uint8_t> OldData,
 }
 
 static Error removeNotes(Object &Obj, endianness Endianness,
-                         ArrayRef<RemoveNoteInfo> NotesToRemove) {
+                         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()) {
-    // TODO: Support note sections in segments
-    if (Sec.Type != SHT_NOTE || Sec.ParentSegment || !Sec.hasContents())
+    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
@@ -885,7 +906,8 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
                      : endianness::big;
 
   if (!ELFConfig.NotesToRemove.empty()) {
-    if (Error Err = removeNotes(Obj, E, ELFConfig.NotesToRemove))
+    if (Error Err =
+            removeNotes(Obj, E, ELFConfig.NotesToRemove, Config.ErrorCallback))
       return Err;
   }
 
diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test
new file mode 100644
index 00000000000000..e664328d7aecf6
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test
@@ -0,0 +1,47 @@
+# RUN: yaml2obj --docnum=1 %s -o %t1
+# RUN: llvm-objcopy --remove-note=1 %t1 %t1o 2>&1 | FileCheck %s --check-prefix=NOTE_SEGMENT
+# NOTE_SEGMENT: warning: note segments are not supported
+# NOTE_SEGMENT-NOT: note segments are not supported
+
+--- !ELF
+FileHeader:
+  Class:          ELFCLASS64
+  Data:           ELFDATA2LSB
+  Type:           ET_EXEC
+  Machine:        EM_X86_64
+ProgramHeaders:
+  - Type:         PT_NOTE
+    FirstSec:     .data0
+    LastSec:      .data0
+  - Type:         PT_NOTE
+    FirstSec:     .data1
+    LastSec:      .data1
+Sections:
+  - Name:         .data0
+    Type:         SHT_PROGBITS
+    AddressAlign: 4
+    Content:      "1122334455"
+  - Name:         .data1
+    Type:         SHT_PROGBITS
+    AddressAlign: 4
+    Content:      "1122334455"
+
+# RUN: yaml2obj --docnum=2 %s -o %t2
+# RUN: llvm-objcopy --remove-note=1 %t2 %t2o 2>&1 | FileCheck %s --check-prefix=NOTE_SECTION
+# NOTE_SECTION: warning: cannot remove note(s) from .note: sections in segments are not supported
+
+--- !ELF
+FileHeader:
+  Class:          ELFCLASS64
+  Data:           ELFDATA2LSB
+  Type:           ET_EXEC
+  Machine:        EM_X86_64
+ProgramHeaders:
+  - Type:         PT_LOAD
+    FirstSec:     .note
+    LastSec:      .note
+Sections:
+  - Name:         .note
+    Type:         SHT_NOTE
+    AddressAlign: 4
+    Content:      "1122334455"
diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
index ad3e60472369bf..7e708e309f207b 100644
--- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -248,6 +248,8 @@ int llvm_objcopy_main(int argc, char **argv, const llvm::ToolContext &) {
     return 1;
   }
   for (ConfigManager &ConfigMgr : DriverConfig->CopyConfigs) {
+    assert(!ConfigMgr.Common.ErrorCallback);
+    ConfigMgr.Common.ErrorCallback = reportWarning;
     if (Error E = executeObjcopy(ConfigMgr)) {
       logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName));
       return 1;

>From b1957e7c706ab631b4a77211b75735dbe69cd564 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Fri, 17 Jan 2025 20:23:55 -0800
Subject: [PATCH 20/21] std::vector<SecPtr>::iterator -> SecPtr&

---
 llvm/lib/ObjCopy/ELF/ELFObject.cpp | 24 +++++++++++-------------
 llvm/lib/ObjCopy/ELF/ELFObject.h   |  3 +--
 2 files changed, 12 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index 2c7a39779220e5..45c7ea49b5d938 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -2154,27 +2154,25 @@ ELFWriter<ELFT>::ELFWriter(Object &Obj, raw_ostream &Buf, bool WSH,
     : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs),
       OnlyKeepDebug(OnlyKeepDebug) {}
 
-Error Object::updateSectionData(std::vector<SecPtr>::iterator It,
-                                ArrayRef<uint8_t> Data) {
-  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",
-        OldSec->Name.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(), OldSec->Name.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();
@@ -2186,14 +2184,14 @@ Error Object::updateSection(StringRef Name, ArrayRef<uint8_t> Data) {
   if (It == Sections.end())
     return createStringError(errc::invalid_argument, "section '%s' not found",
                              Name.str().c_str());
-  return updateSectionData(It, Data);
+  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);
+  return updateSectionData(*It, Data);
 }
 
 Error Object::removeSections(
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h
index 8908187673b024..d8f79a4b1a3cc6 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.h
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.h
@@ -1168,8 +1168,7 @@ class Object {
     return Sec.Flags & ELF::SHF_ALLOC;
   };
 
-  Error updateSectionData(std::vector<SecPtr>::iterator SecIt,
-                          ArrayRef<uint8_t> Data);
+  Error updateSectionData(SecPtr &Sec, ArrayRef<uint8_t> Data);
 
 public:
   template <class T>

>From 9110b2ca3fc291d790bdcd434a5a6f04ce491afa Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Wed, 22 Jan 2025 20:21:14 -0800
Subject: [PATCH 21/21] Move tests from 'remove-note-unsupported.test' to
 'remove-note.test'

---
 .../ELF/remove-note-unsupported.test          | 47 ----------------
 .../tools/llvm-objcopy/ELF/remove-note.test   | 56 +++++++++++++++++--
 2 files changed, 52 insertions(+), 51 deletions(-)
 delete mode 100644 llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test

diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test
deleted file mode 100644
index e664328d7aecf6..00000000000000
--- a/llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test
+++ /dev/null
@@ -1,47 +0,0 @@
-# RUN: yaml2obj --docnum=1 %s -o %t1
-# RUN: llvm-objcopy --remove-note=1 %t1 %t1o 2>&1 | FileCheck %s --check-prefix=NOTE_SEGMENT
-# NOTE_SEGMENT: warning: note segments are not supported
-# NOTE_SEGMENT-NOT: note segments are not supported
-
---- !ELF
-FileHeader:
-  Class:          ELFCLASS64
-  Data:           ELFDATA2LSB
-  Type:           ET_EXEC
-  Machine:        EM_X86_64
-ProgramHeaders:
-  - Type:         PT_NOTE
-    FirstSec:     .data0
-    LastSec:      .data0
-  - Type:         PT_NOTE
-    FirstSec:     .data1
-    LastSec:      .data1
-Sections:
-  - Name:         .data0
-    Type:         SHT_PROGBITS
-    AddressAlign: 4
-    Content:      "1122334455"
-  - Name:         .data1
-    Type:         SHT_PROGBITS
-    AddressAlign: 4
-    Content:      "1122334455"
-
-# RUN: yaml2obj --docnum=2 %s -o %t2
-# RUN: llvm-objcopy --remove-note=1 %t2 %t2o 2>&1 | FileCheck %s --check-prefix=NOTE_SECTION
-# NOTE_SECTION: warning: cannot remove note(s) from .note: sections in segments are not supported
-
---- !ELF
-FileHeader:
-  Class:          ELFCLASS64
-  Data:           ELFDATA2LSB
-  Type:           ET_EXEC
-  Machine:        EM_X86_64
-ProgramHeaders:
-  - Type:         PT_LOAD
-    FirstSec:     .note
-    LastSec:      .note
-Sections:
-  - Name:         .note
-    Type:         SHT_NOTE
-    AddressAlign: 4
-    Content:      "1122334455"
diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
index 06762892e0de5e..f8936bf9ea7312 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/remove-note.test
@@ -24,17 +24,17 @@
 ## * --remove-note=1 will remove note "CORE/1" and "LINUX/1",
 ## * --remove-note=DUMMY/2 will not remove any notes because there are no notes with this owner,
 ## * --remove-note=CORE/3 will remove "CORE/3" but preserve "LINUX/3".
-# RUN: yaml2obj -D ALIGN=8 -D ELFCLASS=64 -D ENDIANNESS=LSB %s -o %t8.64.lsb
+# RUN: yaml2obj --docnum=1 -D ALIGN=8 -D ELFCLASS=64 -D ENDIANNESS=LSB %s -o %t8.64.lsb
 # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8.64.lsb %t8.64.lsb.o
 # RUN: llvm-readobj --segments --sections --notes %t8.64.lsb.o | \
 # RUN:   FileCheck %s -D#SIZE0=32 -D#SIZE1=64
 
-# RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=64 -D ENDIANNESS=MSB %s -o %t4.64.msb
+# RUN: yaml2obj --docnum=1 -D ALIGN=4 -D ELFCLASS=64 -D ENDIANNESS=MSB %s -o %t4.64.msb
 # RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.64.msb %t4.64.msb.o
 # RUN: llvm-readobj --segments --sections --notes %t4.64.msb.o | \
 # RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=48
 
-# RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=32 -D ENDIANNESS=LSB %s -o %t4.32.lsb
+# RUN: yaml2obj --docnum=1 -D ALIGN=4 -D ELFCLASS=32 -D ENDIANNESS=LSB %s -o %t4.32.lsb
 # RUN: llvm-objcopy --remove-note=1 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.32.lsb %t4.32.lsb.o
 # RUN: llvm-readobj --segments --sections --notes %t4.32.lsb.o | \
 # RUN:   FileCheck %s -D#SIZE0=24 -D#SIZE1=48
@@ -147,4 +147,52 @@ Sections:
       - Name:   LINUX
         Type:   0x01
         Desc:   0102
-...
+
+# RUN: yaml2obj --docnum=2 %s -o %t2
+# RUN: llvm-objcopy --remove-note=1 %t2 %t2o 2>&1 | FileCheck %s --check-prefix=TEST2
+# TEST2: warning: note segments are not supported
+# TEST2-NOT: note segments are not supported
+
+--- !ELF
+FileHeader:
+  Class:          ELFCLASS64
+  Data:           ELFDATA2LSB
+  Type:           ET_CORE
+  Machine:        EM_X86_64
+ProgramHeaders:
+  - Type:         PT_NOTE
+    FirstSec:     .data0
+    LastSec:      .data0
+  - Type:         PT_NOTE
+    FirstSec:     .data1
+    LastSec:      .data1
+Sections:
+  - Name:         .data0
+    Type:         Fill
+    Size:         8
+  - Name:         .data1
+    Type:         Fill
+    Size:         8
+
+# RUN: yaml2obj --docnum=3 %s -o %t3
+# RUN: llvm-objcopy --remove-note=1 %t3 %t3o 2>&1 | FileCheck %s --check-prefix=TEST3
+# TEST3: warning: cannot remove note(s) from .note: sections in segments are not supported
+
+--- !ELF
+FileHeader:
+  Class:          ELFCLASS64
+  Data:           ELFDATA2LSB
+  Type:           ET_EXEC
+  Machine:        EM_X86_64
+ProgramHeaders:
+  - Type:         PT_LOAD
+    FirstSec:     .note
+    LastSec:      .note
+Sections:
+  - Name:         .note
+    Type:         SHT_NOTE
+    AddressAlign: 4
+    Notes:
+      - Name:     ABC
+        Type:     1
+        Desc:     0102



More information about the llvm-commits mailing list