[llvm] [yaml2obj] Allow the creation of note segments without sections (PR #123704)
Igor Kudrin via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 20 23:38:07 PST 2025
https://github.com/igorkudrin created https://github.com/llvm/llvm-project/pull/123704
This adds a new section type, `NoteChunk`, which, provides its content to a segment, but does not create an ELF section. This makes it possible to generate ELF core files, where note segments do not have associated sections.
>From 56a77a9b749050d72bb53f7f44e54564be73808d Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Mon, 20 Jan 2025 23:15:26 -0800
Subject: [PATCH] [yaml2obj] Allow the creation of note segments without
sections
This adds a new section type, 'NoteChunk', which, provides its content
to a segment, but does not create an ELF section. This makes it possible
to generate ELF core files, where note segments do not have associated
sections.
---
llvm/include/llvm/ObjectYAML/ELFYAML.h | 15 +++
llvm/lib/ObjectYAML/ELFEmitter.cpp | 75 ++++++++---
llvm/lib/ObjectYAML/ELFYAML.cpp | 18 +++
.../test/tools/yaml2obj/ELF/note-segment.yaml | 127 ++++++++++++++++++
4 files changed, 215 insertions(+), 20 deletions(-)
create mode 100644 llvm/test/tools/yaml2obj/ELF/note-segment.yaml
diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index dfdfa055d65fa6..104c17bf34b9e4 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -234,6 +234,7 @@ struct Chunk {
SpecialChunksStart,
Fill = SpecialChunksStart,
SectionHeaderTable,
+ NoteChunk,
};
ChunkKind Kind;
@@ -340,6 +341,20 @@ struct SectionHeaderTable : Chunk {
static constexpr StringRef TypeStr = "SectionHeaderTable";
};
+struct NoteChunk : Chunk {
+ llvm::yaml::Hex64 NoteAlign;
+ std::vector<ELFYAML::NoteEntry> Notes;
+ uint64_t Size = 0;
+
+ NoteChunk() : Chunk(ChunkKind::NoteChunk, /*Implicit=*/false) {}
+
+ static bool classof(const Chunk *S) {
+ return S->Kind == ChunkKind::NoteChunk;
+ }
+
+ static constexpr StringRef TypeStr = "NoteChunk";
+};
+
struct BBAddrMapSection : Section {
std::optional<std::vector<BBAddrMapEntry>> Entries;
std::optional<std::vector<PGOAnalysisMapEntry>> PGOAnalyses;
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index cc41bbe6bbde24..44830571a76e5c 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -310,6 +310,11 @@ template <class ELFT> class ELFState {
ContiguousBlobAccumulator &CBA);
void writeFill(ELFYAML::Fill &Fill, ContiguousBlobAccumulator &CBA);
+ void writeNoteChunk(ELFYAML::NoteChunk &NoteChunk,
+ ContiguousBlobAccumulator &CBA);
+
+ uint64_t writeNotes(StringRef SecName, ArrayRef<ELFYAML::NoteEntry> Notes,
+ uint64_t Align, ContiguousBlobAccumulator &CBA);
ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH);
@@ -792,6 +797,13 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
continue;
}
+ if (ELFYAML::NoteChunk *S = dyn_cast<ELFYAML::NoteChunk>(D.get())) {
+ S->Offset = alignToOffset(CBA, S->NoteAlign, S->Offset);
+ writeNoteChunk(*S, CBA);
+ LocationCounter += S->Size;
+ continue;
+ }
+
ELFYAML::Section *Sec = cast<ELFYAML::Section>(D.get());
bool IsFirstUndefSection = Sec == Doc.getSections().front();
if (IsFirstUndefSection && Sec->IsImplicit)
@@ -1157,6 +1169,11 @@ ELFState<ELFT>::getPhdrFragments(const ELFYAML::ProgramHeader &Phdr,
/*ShAddrAlign=*/1});
continue;
}
+ if (const auto *F = dyn_cast<ELFYAML::NoteChunk>(C)) {
+ Ret.push_back(
+ {*F->Offset, F->Size, llvm::ELF::SHT_PROGBITS, F->NoteAlign});
+ continue;
+ }
const ELFYAML::Section *S = cast<ELFYAML::Section>(C);
const Elf_Shdr &H = SHeaders[SN2I.get(S->Name)];
@@ -1229,7 +1246,7 @@ bool llvm::ELFYAML::shouldAllocateFileSpace(
auto It = llvm::find_if(
PH.Chunks, [&](ELFYAML::Chunk *C) { return C->Name == S.Name; });
if (std::any_of(It, PH.Chunks.end(), [](ELFYAML::Chunk *C) {
- return (isa<ELFYAML::Fill>(C) ||
+ return (!isa<ELFYAML::Section>(C) ||
cast<ELFYAML::Section>(C)->Type != ELF::SHT_NOBITS);
}))
return true;
@@ -1793,36 +1810,35 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
}
template <class ELFT>
-void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
- const ELFYAML::NoteSection &Section,
- ContiguousBlobAccumulator &CBA) {
- if (!Section.Notes || Section.Notes->empty())
- return;
+uint64_t ELFState<ELFT>::writeNotes(StringRef SecName,
+ ArrayRef<ELFYAML::NoteEntry> Notes,
+ uint64_t Align,
+ ContiguousBlobAccumulator &CBA) {
+ if (Notes.empty())
+ return 0;
- unsigned Align;
- switch (Section.AddressAlign) {
+ switch (Align) {
case 0:
- case 4:
Align = 4;
- break;
+ [[fallthrough]];
+ case 4:
case 8:
- Align = 8;
break;
default:
- reportError(Section.Name + ": invalid alignment for a note section: 0x" +
- Twine::utohexstr(Section.AddressAlign));
- return;
+ reportError(SecName + ": invalid alignment for a note section: 0x" +
+ Twine::utohexstr(Align));
+ return 0;
}
if (CBA.getOffset() != alignTo(CBA.getOffset(), Align)) {
- reportError(Section.Name + ": invalid offset of a note section: 0x" +
+ reportError(SecName + ": invalid offset of a note section: 0x" +
Twine::utohexstr(CBA.getOffset()) + ", should be aligned to " +
Twine(Align));
- return;
+ return 0;
}
uint64_t Offset = CBA.tell();
- for (const ELFYAML::NoteEntry &NE : *Section.Notes) {
+ for (const ELFYAML::NoteEntry &NE : Notes) {
// Write name size.
if (NE.Name.empty())
CBA.write<uint32_t>(0, ELFT::Endianness);
@@ -1838,22 +1854,41 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
// Write type.
CBA.write<uint32_t>(NE.Type, ELFT::Endianness);
- // Write name, null terminator and padding.
+ // Write name and the null terminator.
if (!NE.Name.empty()) {
CBA.write(NE.Name.data(), NE.Name.size());
CBA.write('\0');
}
- // Write description and padding.
+ // Write description, padding to the alignment.
if (NE.Desc.binary_size() != 0) {
CBA.padToAlignment(Align);
CBA.writeAsBinary(NE.Desc);
}
+ // Write the padding for the next entry.
CBA.padToAlignment(Align);
}
- SHeader.sh_size = CBA.tell() - Offset;
+ return CBA.tell() - Offset;
+}
+
+template <class ELFT>
+void ELFState<ELFT>::writeNoteChunk(ELFYAML::NoteChunk &NoteChunk,
+ ContiguousBlobAccumulator &CBA) {
+ NoteChunk.Size =
+ writeNotes(NoteChunk.Name, NoteChunk.Notes, NoteChunk.NoteAlign, CBA);
+}
+
+template <class ELFT>
+void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
+ const ELFYAML::NoteSection &Section,
+ ContiguousBlobAccumulator &CBA) {
+ if (!Section.Notes)
+ return;
+
+ SHeader.sh_size =
+ writeNotes(Section.Name, *Section.Notes, Section.AddressAlign, CBA);
}
template <class ELFT>
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 7e94d01a971534..550aa3fed6f043 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -1525,6 +1525,13 @@ static void sectionHeaderTableMapping(IO &IO,
IO.mapOptional("NoHeaders", SHT.NoHeaders);
}
+static void noteChunkMapping(IO &IO, ELFYAML::NoteChunk &Chunk) {
+ IO.mapOptional("Name", Chunk.Name, StringRef());
+ IO.mapOptional("Offset", Chunk.Offset);
+ IO.mapOptional("NoteAlign", Chunk.NoteAlign, Hex64(4));
+ IO.mapRequired("Notes", Chunk.Notes);
+}
+
static void sectionMapping(IO &IO, ELFYAML::LinkerOptionsSection &Section) {
commonSectionMapping(IO, Section);
IO.mapOptional("Options", Section.Options);
@@ -1621,6 +1628,14 @@ void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
return;
}
+ if (TypeStr == ELFYAML::NoteChunk::TypeStr) {
+ assert(!IO.outputting()); // We don't dump note chunks currently.
+ Section.reset(new ELFYAML::NoteChunk());
+ noteChunkMapping(IO, *cast<ELFYAML::NoteChunk>(Section.get()));
+ return;
+ }
+
+
const auto &Obj = *static_cast<ELFYAML::Object *>(IO.getContext());
if (Obj.getMachine() == ELF::EM_MIPS && Type == ELF::SHT_MIPS_ABIFLAGS) {
if (!IO.outputting())
@@ -1758,6 +1773,9 @@ std::string MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::validate(
return "";
}
+ if (isa<ELFYAML::NoteChunk>(C.get()))
+ return "";
+
const ELFYAML::Section &Sec = *cast<ELFYAML::Section>(C.get());
if (Sec.Size && Sec.Content &&
(uint64_t)(*Sec.Size) < Sec.Content->binary_size())
diff --git a/llvm/test/tools/yaml2obj/ELF/note-segment.yaml b/llvm/test/tools/yaml2obj/ELF/note-segment.yaml
new file mode 100644
index 00000000000000..777c50468fb4f1
--- /dev/null
+++ b/llvm/test/tools/yaml2obj/ELF/note-segment.yaml
@@ -0,0 +1,127 @@
+## Check that NoteChunks can generate note content for a segment without
+## creating note sections.
+
+# RUN: yaml2obj --docnum=1 -D ENDIANNESS=LSB -D ALIGN=4 %s -o %t1.lsb4
+# RUN: llvm-readelf --segments --sections --notes %t1.lsb4 | \
+# RUN: FileCheck %s --check-prefix=TEST1 -D#SIZE0=24 -D#SIZE1=20 -D#SIZE2=20 -D#ALIGN=4
+
+# RUN: yaml2obj --docnum=1 -D ENDIANNESS=MSB -D ALIGN=8 %s -o %t1.msb8
+# RUN: llvm-readelf --segments --sections --notes %t1.msb8 | \
+# RUN: FileCheck %s --check-prefix=TEST1 -D#SIZE0=32 -D#SIZE1=24 -D#SIZE2=24 -D#ALIGN=8
+
+# TEST1: Section Headers:
+# TEST1-NEXT: [Nr] Name Type Address Off Size
+# TEST1-NEXT: [ 0] NULL
+# TEST1-NEXT: [ 1] .note1 NOTE [[#%x,]] [[#%x,OFFSET1:]] [[#%.6x,SIZE1]]
+# TEST1-NEXT: [ 2] .strtab
+# TEST1-NEXT: [ 3] .shstrtab
+#
+# TEST1: Program Headers:
+# TEST1-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
+# TEST1-NEXT: NOTE [[#%#.6x,OFFSET1-SIZE0]] [[#%#x,]] [[#%#x,]] [[#%#.6x,SIZE0+SIZE1+SIZE2]] [[#%#.6x,SIZE0+SIZE1+SIZE2]] [[#%#x,ALIGN]]
+#
+# TEST1: Section to Segment mapping:
+# TEST1-NEXT: Segment Sections...
+# TEST1-NEXT: 00 .note1{{[ ]*$}}
+#
+# TEST1: Displaying notes found at file offset [[#%#.8x,== OFFSET1-SIZE0]] with length [[#%#.8x,SIZE0+SIZE1+SIZE2]]:
+# TEST1-NEXT: Owner Data size Description
+# TEST1-NEXT: ABCD 0x00000002 NT_PRSTATUS
+# TEST1-NEXT: description data: 01 02
+# TEST1-NEXT: EFG 0x00000002 NT_FPREGSET
+# TEST1-NEXT: description data: 03 04
+# TEST1-NEXT: XYZ 0x00000002 NT_PRPSINFO
+# TEST1-NEXT: description data: 05 06
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2[[ENDIANNESS]]
+ Type: ET_CORE
+ProgramHeaders:
+ - Type: PT_NOTE
+ FirstSec: .note0
+ LastSec: .note2
+Sections:
+ - Name: .note0
+ Type: NoteChunk
+ NoteAlign: [[ALIGN]]
+ Notes:
+ - Name: ABCD
+ Type: 0x1
+ Desc: 0102
+ - Name: .note1
+ Type: SHT_NOTE
+ AddressAlign: [[ALIGN]]
+ Notes:
+ - Name: EFG
+ Type: 0x2
+ Desc: 0304
+ - Name: .note2
+ Type: NoteChunk
+ NoteAlign: [[ALIGN]]
+ Notes:
+ - Name: XYZ
+ Type: 0x3
+ Desc: 0506
+
+## Check the default value for 'NoteAlign'
+
+# RUN: yaml2obj --docnum=2 %s -o %t2
+# RUN: llvm-readelf --segments %t2 | FileCheck %s --check-prefix=TEST2
+
+# TEST2: Program Headers:
+# TEST2-NEXT: Type {{.*}} Align{{$}}
+# TEST2-NEXT: NOTE {{.*}} 0x4{{$}}
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_CORE
+ProgramHeaders:
+ - Type: PT_NOTE
+ FirstSec: .note0
+ LastSec: .note0
+Sections:
+ - Name: .note0
+ Type: NoteChunk
+ Notes:
+ - Name: ABCD
+ Type: 0x1
+ Desc: 0102
+
+## Check that an incorrect alignment is reported.
+
+# RUN: not yaml2obj --docnum=3 %s 2>&1 | FileCheck %s --check-prefix=TEST3
+# TEST3: error: .note0: invalid alignment for a note section: 0x1
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+Sections:
+ - Name: .note0
+ Type: NoteChunk
+ NoteAlign: 1
+ Notes:
+ - Type: 0x1
+
+## Check that an incorrect offset for generating notes is reported.
+
+# RUN: not yaml2obj --docnum=4 %s 2>&1 | FileCheck %s --check-prefix=TEST4
+# TEST4: error: .note: invalid offset of a note section: 0x504, should be aligned to 8
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+Sections:
+ - Name: .note
+ Type: NoteChunk
+ Offset: 0x504
+ NoteAlign: 8
+ Notes:
+ - Type: 0x1
More information about the llvm-commits
mailing list