Skip to content

Commit 1077280

Browse files
committed
Reapply "[llvm-objcopy][ELF] Add an option to remove notes (#118739)"
This fixes "unused-local-typedef" warnings in 9324e6a. This adds an option `--remove-note=[name/]type` to selectively delete notes in ELF files, where `type` is the numeric value of the note type and `name` is the name of the originator. The name can be omitted, in which case all notes of the specified type will be removed. For now, only `SHT_NOTE` sections that are not associated with segments are handled. The implementation can be extended later as needed. RFC: https://discourse.llvm.org/t/rfc-llvm-objcopy-feature-for-editing-notes/83491
1 parent 3d59e30 commit 1077280

File tree

10 files changed

+423
-16
lines changed

10 files changed

+423
-16
lines changed

llvm/docs/CommandGuide/llvm-objcopy.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,11 @@ them.
477477

478478
Preserve access and modification timestamps in the output.
479479

480+
.. option:: --remove-note [<name>/]<type>
481+
482+
Remove notes of integer type ``<type>`` and name ``<name>`` from SHT_NOTE
483+
sections that are not in a segment. Can be specified multiple times.
484+
480485
.. option:: --rename-section <old>=<new>[,<flag>,...]
481486

482487
Rename sections called ``<old>`` to ``<new>`` in the output, and apply any

llvm/include/llvm/ObjCopy/CommonConfig.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,11 @@ struct CommonConfig {
281281

282282
SmallVector<std::pair<NameMatcher, llvm::DebugCompressionType>, 0>
283283
compressSections;
284+
285+
// ErrorCallback is used to handle recoverable errors. An Error returned
286+
// by the callback aborts the execution and is then returned to the caller.
287+
// If the callback is not set, the errors are not issued.
288+
std::function<Error(Error)> ErrorCallback;
284289
};
285290

286291
} // namespace objcopy

llvm/include/llvm/ObjCopy/ELF/ELFConfig.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
namespace llvm {
1616
namespace objcopy {
1717

18+
// Note to remove info specified by --remove-note option.
19+
struct RemoveNoteInfo {
20+
StringRef Name;
21+
uint32_t TypeId;
22+
};
23+
1824
// ELF specific configuration for copying/stripping a single file.
1925
struct ELFConfig {
2026
uint8_t NewSymbolVisibility = (uint8_t)ELF::STV_DEFAULT;
@@ -31,6 +37,9 @@ struct ELFConfig {
3137
bool KeepFileSymbols = false;
3238
bool LocalizeHidden = false;
3339
bool VerifyNoteSections = true;
40+
41+
// Notes specified by --remove-note option.
42+
SmallVector<RemoveNoteInfo, 0> NotesToRemove;
3443
};
3544

3645
} // namespace objcopy

llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,113 @@ static void addSymbol(Object &Obj, const NewSymbolInfo &SymInfo,
609609
Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0);
610610
}
611611

612+
namespace {
613+
struct RemoveNoteDetail {
614+
struct DeletedRange {
615+
uint64_t OldFrom;
616+
uint64_t OldTo;
617+
};
618+
619+
template <class ELFT>
620+
static std::vector<DeletedRange>
621+
findNotesToRemove(ArrayRef<uint8_t> Data, size_t Align,
622+
ArrayRef<RemoveNoteInfo> NotesToRemove);
623+
static std::vector<uint8_t> updateData(ArrayRef<uint8_t> OldData,
624+
ArrayRef<DeletedRange> ToRemove);
625+
};
626+
} // namespace
627+
628+
template <class ELFT>
629+
std::vector<RemoveNoteDetail::DeletedRange>
630+
RemoveNoteDetail::findNotesToRemove(ArrayRef<uint8_t> Data, size_t Align,
631+
ArrayRef<RemoveNoteInfo> NotesToRemove) {
632+
using Elf_Nhdr = typename ELFT::Nhdr;
633+
using Elf_Note = typename ELFT::Note;
634+
std::vector<DeletedRange> ToRemove;
635+
uint64_t CurPos = 0;
636+
while (CurPos + sizeof(Elf_Nhdr) <= Data.size()) {
637+
auto Nhdr = reinterpret_cast<const Elf_Nhdr *>(Data.data() + CurPos);
638+
size_t FullSize = Nhdr->getSize(Align);
639+
if (CurPos + FullSize > Data.size())
640+
break;
641+
Elf_Note Note(*Nhdr);
642+
bool ShouldRemove =
643+
llvm::any_of(NotesToRemove, [&Note](const RemoveNoteInfo &NoteInfo) {
644+
return NoteInfo.TypeId == Note.getType() &&
645+
(NoteInfo.Name.empty() || NoteInfo.Name == Note.getName());
646+
});
647+
if (ShouldRemove)
648+
ToRemove.push_back({CurPos, CurPos + FullSize});
649+
CurPos += FullSize;
650+
}
651+
return ToRemove;
652+
}
653+
654+
std::vector<uint8_t>
655+
RemoveNoteDetail::updateData(ArrayRef<uint8_t> OldData,
656+
ArrayRef<DeletedRange> ToRemove) {
657+
std::vector<uint8_t> NewData;
658+
NewData.reserve(OldData.size());
659+
uint64_t CurPos = 0;
660+
for (const DeletedRange &RemRange : ToRemove) {
661+
if (CurPos < RemRange.OldFrom) {
662+
auto Slice = OldData.slice(CurPos, RemRange.OldFrom - CurPos);
663+
NewData.insert(NewData.end(), Slice.begin(), Slice.end());
664+
}
665+
CurPos = RemRange.OldTo;
666+
}
667+
if (CurPos < OldData.size()) {
668+
auto Slice = OldData.slice(CurPos);
669+
NewData.insert(NewData.end(), Slice.begin(), Slice.end());
670+
}
671+
return NewData;
672+
}
673+
674+
static Error removeNotes(Object &Obj, endianness Endianness,
675+
ArrayRef<RemoveNoteInfo> NotesToRemove,
676+
function_ref<Error(Error)> ErrorCallback) {
677+
// TODO: Support note segments.
678+
if (ErrorCallback) {
679+
for (Segment &Seg : Obj.segments()) {
680+
if (Seg.Type == PT_NOTE) {
681+
if (Error E = ErrorCallback(createStringError(
682+
errc::not_supported, "note segments are not supported")))
683+
return E;
684+
break;
685+
}
686+
}
687+
}
688+
for (auto &Sec : Obj.sections()) {
689+
if (Sec.Type != SHT_NOTE || !Sec.hasContents())
690+
continue;
691+
// TODO: Support note sections in segments.
692+
if (Sec.ParentSegment) {
693+
if (ErrorCallback)
694+
if (Error E = ErrorCallback(createStringError(
695+
errc::not_supported,
696+
"cannot remove note(s) from " + Sec.Name +
697+
": sections in segments are not supported")))
698+
return E;
699+
continue;
700+
}
701+
ArrayRef<uint8_t> OldData = Sec.getContents();
702+
size_t Align = std::max<size_t>(4, Sec.Align);
703+
// Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the
704+
// header, so the parsers are the same.
705+
auto ToRemove = (Endianness == endianness::little)
706+
? RemoveNoteDetail::findNotesToRemove<ELF64LE>(
707+
OldData, Align, NotesToRemove)
708+
: RemoveNoteDetail::findNotesToRemove<ELF64BE>(
709+
OldData, Align, NotesToRemove);
710+
if (!ToRemove.empty()) {
711+
if (Error E = Obj.updateSectionData(
712+
Sec, RemoveNoteDetail::updateData(OldData, ToRemove)))
713+
return E;
714+
}
715+
}
716+
return Error::success();
717+
}
718+
612719
static Error
613720
handleUserSection(const NewSectionInfo &NewSection,
614721
function_ref<Error(StringRef, ArrayRef<uint8_t>)> F) {
@@ -799,6 +906,12 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
799906
? endianness::little
800907
: endianness::big;
801908

909+
if (!ELFConfig.NotesToRemove.empty()) {
910+
if (Error Err =
911+
removeNotes(Obj, E, ELFConfig.NotesToRemove, Config.ErrorCallback))
912+
return Err;
913+
}
914+
802915
for (const NewSectionInfo &AddedSection : Config.AddSection) {
803916
auto AddSection = [&](StringRef Name, ArrayRef<uint8_t> Data) -> Error {
804917
OwnedDataSection &NewSection =

llvm/lib/ObjCopy/ELF/ELFObject.cpp

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2154,37 +2154,46 @@ ELFWriter<ELFT>::ELFWriter(Object &Obj, raw_ostream &Buf, bool WSH,
21542154
: Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs),
21552155
OnlyKeepDebug(OnlyKeepDebug) {}
21562156

2157-
Error Object::updateSection(StringRef Name, ArrayRef<uint8_t> Data) {
2158-
auto It = llvm::find_if(Sections,
2159-
[&](const SecPtr &Sec) { return Sec->Name == Name; });
2160-
if (It == Sections.end())
2161-
return createStringError(errc::invalid_argument, "section '%s' not found",
2162-
Name.str().c_str());
2163-
2164-
auto *OldSec = It->get();
2165-
if (!OldSec->hasContents())
2157+
Error Object::updateSectionData(SecPtr &Sec, ArrayRef<uint8_t> Data) {
2158+
if (!Sec->hasContents())
21662159
return createStringError(
21672160
errc::invalid_argument,
21682161
"section '%s' cannot be updated because it does not have contents",
2169-
Name.str().c_str());
2162+
Sec->Name.c_str());
21702163

2171-
if (Data.size() > OldSec->Size && OldSec->ParentSegment)
2164+
if (Data.size() > Sec->Size && Sec->ParentSegment)
21722165
return createStringError(errc::invalid_argument,
21732166
"cannot fit data of size %zu into section '%s' "
21742167
"with size %" PRIu64 " that is part of a segment",
2175-
Data.size(), Name.str().c_str(), OldSec->Size);
2168+
Data.size(), Sec->Name.c_str(), Sec->Size);
21762169

2177-
if (!OldSec->ParentSegment) {
2178-
*It = std::make_unique<OwnedDataSection>(*OldSec, Data);
2170+
if (!Sec->ParentSegment) {
2171+
Sec = std::make_unique<OwnedDataSection>(*Sec, Data);
21792172
} else {
21802173
// The segment writer will be in charge of updating these contents.
2181-
OldSec->Size = Data.size();
2182-
UpdatedSections[OldSec] = Data;
2174+
Sec->Size = Data.size();
2175+
UpdatedSections[Sec.get()] = Data;
21832176
}
21842177

21852178
return Error::success();
21862179
}
21872180

2181+
Error Object::updateSection(StringRef Name, ArrayRef<uint8_t> Data) {
2182+
auto It = llvm::find_if(Sections,
2183+
[&](const SecPtr &Sec) { return Sec->Name == Name; });
2184+
if (It == Sections.end())
2185+
return createStringError(errc::invalid_argument, "section '%s' not found",
2186+
Name.str().c_str());
2187+
return updateSectionData(*It, Data);
2188+
}
2189+
2190+
Error Object::updateSectionData(SectionBase &S, ArrayRef<uint8_t> Data) {
2191+
auto It = llvm::find_if(Sections,
2192+
[&](const SecPtr &Sec) { return Sec.get() == &S; });
2193+
assert(It != Sections.end() && "The section should belong to the object");
2194+
return updateSectionData(*It, Data);
2195+
}
2196+
21882197
Error Object::removeSections(
21892198
bool AllowBrokenLinks, std::function<bool(const SectionBase &)> ToRemove) {
21902199

llvm/lib/ObjCopy/ELF/ELFObject.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ class SectionBase {
549549
virtual void
550550
replaceSectionReferences(const DenseMap<SectionBase *, SectionBase *> &);
551551
virtual bool hasContents() const { return false; }
552+
virtual ArrayRef<uint8_t> getContents() const { return {}; }
552553
// Notify the section that it is subject to removal.
553554
virtual void onRemove();
554555

@@ -619,6 +620,8 @@ class Section : public SectionBase {
619620
bool hasContents() const override {
620621
return Type != ELF::SHT_NOBITS && Type != ELF::SHT_NULL;
621622
}
623+
ArrayRef<uint8_t> getContents() const override { return Contents; }
624+
622625
void restoreSymTabLink(SymbolTableSection &SymTab) override;
623626
};
624627

@@ -654,6 +657,7 @@ class OwnedDataSection : public SectionBase {
654657
Error accept(SectionVisitor &Sec) const override;
655658
Error accept(MutableSectionVisitor &Visitor) override;
656659
bool hasContents() const override { return true; }
660+
ArrayRef<uint8_t> getContents() const override { return Data; }
657661
};
658662

659663
class CompressedSection : public SectionBase {
@@ -1164,6 +1168,8 @@ class Object {
11641168
return Sec.Flags & ELF::SHF_ALLOC;
11651169
};
11661170

1171+
Error updateSectionData(SecPtr &Sec, ArrayRef<uint8_t> Data);
1172+
11671173
public:
11681174
template <class T>
11691175
using ConstRange = iterator_range<pointee_iterator<
@@ -1206,6 +1212,7 @@ class Object {
12061212

12071213
const auto &getUpdatedSections() const { return UpdatedSections; }
12081214
Error updateSection(StringRef Name, ArrayRef<uint8_t> Data);
1215+
Error updateSectionData(SectionBase &S, ArrayRef<uint8_t> Data);
12091216

12101217
SectionBase *findSection(StringRef Name) {
12111218
auto SecIt =

0 commit comments

Comments
 (0)