https://github.com/steffenlarsen updated https://github.com/llvm/llvm-project/pull/214135
>From 8af2e41c4def005000f304343c171946f598eacb Mon Sep 17 00:00:00 2001 From: Steffen Holst Larsen <[email protected]> Date: Tue, 4 Aug 2026 01:04:45 -0500 Subject: [PATCH 1/5] [Clang][PCH] Use metadata for embedding AST To avoid the size restriction that may be imposed by the address spaces of the target, this patch changes the embedding of the Clang AST from placing it inside a global variable to placing it inside a metadata node. This is done by introducing a new metadata node, namely `llvm.raw.sections`, which refers to nodes comprised of a section name, an alignment and the section data. The AsmPrinter lowers this to the corresponding sections. Assisted-by: Claude Opus 4.6 Signed-off-by: Steffen Holst Larsen <[email protected]> --- .../CodeGen/ObjectFilePCHContainerWriter.cpp | 34 ++++++++++--------- clang/test/Modules/lsv-debuginfo.cpp | 9 +++-- clang/test/PCH/pch-clangast-raw-section.c | 6 ++++ .../CodeGen/TargetLoweringObjectFileImpl.h | 8 +++++ .../llvm/Target/TargetLoweringObjectFile.h | 7 ++++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 21 ++++++++++++ .../CodeGen/TargetLoweringObjectFileImpl.cpp | 23 +++++++++++++ .../CodeGen/WebAssembly/raw-sections-wasm.ll | 7 ++++ llvm/test/CodeGen/X86/raw-sections-coff.ll | 12 +++++++ llvm/test/CodeGen/X86/raw-sections-elf.ll | 7 ++++ llvm/test/CodeGen/X86/raw-sections-macho.ll | 9 +++++ 11 files changed, 124 insertions(+), 19 deletions(-) create mode 100644 clang/test/PCH/pch-clangast-raw-section.c create mode 100644 llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll create mode 100644 llvm/test/CodeGen/X86/raw-sections-coff.ll create mode 100644 llvm/test/CodeGen/X86/raw-sections-elf.ll create mode 100644 llvm/test/CodeGen/X86/raw-sections-macho.ll diff --git a/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp b/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp index 074f2a520704d..3a507782bb66e 100644 --- a/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp +++ b/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp @@ -297,25 +297,27 @@ class PCHContainerGenerator : public ASTConsumer { auto *NameAndContent = llvm::MDTuple::get(*VMContext, Ops); MD->addOperand(NameAndContent); } else { - auto Int8Ty = llvm::Type::getInt8Ty(*VMContext); - auto *Ty = llvm::ArrayType::get(Int8Ty, Size); - auto *Data = llvm::ConstantDataArray::getString( - *VMContext, StringRef(SerializedAST.data(), Size), - /*AddNull=*/false); - auto *ASTSym = new llvm::GlobalVariable( - *M, Ty, /*constant*/ true, llvm::GlobalVariable::InternalLinkage, - Data, "__clang_ast"); - // The on-disk hashtable needs to be aligned. - ASTSym->setAlignment(llvm::Align(8)); - - // Mach-O also needs a segment name. + // Emit the serialized AST into a named section via llvm.raw.sections + // metadata, which the AsmPrinter emits directly at the MC layer. + // This avoids IR-level size constraints from the target's address space. + llvm::NamedMDNode *RawSections = + M->getOrInsertNamedMetadata("llvm.raw.sections"); + + StringRef SectionName; if (Triple.isOSBinFormatMachO()) - ASTSym->setSection("__CLANG,__clangast"); - // COFF has an eight character length limit. + SectionName = "__CLANG,__clangast"; else if (Triple.isOSBinFormatCOFF()) - ASTSym->setSection("clangast"); + SectionName = "clangast"; else - ASTSym->setSection("__clangast"); + SectionName = "__clangast"; + + llvm::Metadata *Ops[] = { + llvm::MDString::get(*VMContext, SectionName), + llvm::ConstantAsMetadata::get( + llvm::ConstantInt::get(llvm::Type::getInt32Ty(*VMContext), 8)), + llvm::MDString::get(*VMContext, + StringRef(SerializedAST.data(), Size))}; + RawSections->addOperand(llvm::MDTuple::get(*VMContext, Ops)); } LLVM_DEBUG({ diff --git a/clang/test/Modules/lsv-debuginfo.cpp b/clang/test/Modules/lsv-debuginfo.cpp index 40455727ecdda..61d2ff9514ed3 100644 --- a/clang/test/Modules/lsv-debuginfo.cpp +++ b/clang/test/Modules/lsv-debuginfo.cpp @@ -21,17 +21,20 @@ // RUN: cat %t-mod.ll | FileCheck %s // ADT -// CHECK: @__clang_ast = +// CHECK: !llvm.raw.sections = !{[[ADT_SEC:![0-9]+]]} +// CHECK: [[ADT_SEC]] = !{!"__clangast", // B -// CHECK: @__clang_ast = +// CHECK: !llvm.raw.sections = !{[[B_SEC:![0-9]+]]} +// CHECK: [[B_SEC]] = !{!"__clangast", // This type isn't anchored anywhere, expect a full definition. // CHECK: !DICompositeType({{.*}}, name: "AlignedCharArray<4U, 16U>", // CHECK-SAME: elements: // C -// CHECK: @__clang_ast = +// CHECK: !llvm.raw.sections = !{[[C_SEC:![0-9]+]]} +// CHECK: [[C_SEC]] = !{!"__clangast", // Here, too. // CHECK: !DICompositeType({{.*}}, name: "AlignedCharArray<4U, 16U>", diff --git a/clang/test/PCH/pch-clangast-raw-section.c b/clang/test/PCH/pch-clangast-raw-section.c new file mode 100644 index 0000000000000..2ef54cf640e1c --- /dev/null +++ b/clang/test/PCH/pch-clangast-raw-section.c @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-pch -fmodule-format=obj %S/pchpch1.h -o - | llvm-readelf --sections - | FileCheck %s + +// Ensure the serialized AST is emitted via llvm.raw.sections metadata into +// a __clangast section with 8-byte alignment. + +// CHECK: __clangast PROGBITS {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} 00 A 0 0 8 diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h index 78954a8bb2121..a56e8ed6e0879 100644 --- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -49,6 +49,8 @@ class LLVM_ABI TargetLoweringObjectFileELF : public TargetLoweringObjectFile { /// Emit Obj-C garbage collection and linker options. void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override; + MCSection *getNamedReadOnlySection(StringRef Name) const override; + void emitPersonalityValue(MCStreamer &Streamer, const DataLayout &DL, const MCSymbol *Sym, const MachineModuleInfo *MMI) const override; @@ -144,6 +146,8 @@ class LLVM_ABI TargetLoweringObjectFileMachO : public TargetLoweringObjectFile { /// Emit the module flags that specify the garbage collection information. void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override; + MCSection *getNamedReadOnlySection(StringRef Name) const override; + void emitLinkerDirectives(MCStreamer &Streamer, Module &M) const override; MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, @@ -207,6 +211,8 @@ class LLVM_ABI TargetLoweringObjectFileCOFF : public TargetLoweringObjectFile { /// Emit Obj-C garbage collection and linker options. void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override; + MCSection *getNamedReadOnlySection(StringRef Name) const override; + void emitLinkerDirectives(MCStreamer &Streamer, Module &M) const override; MCSection *getStaticCtorSection(unsigned Priority, @@ -245,6 +251,8 @@ class LLVM_ABI TargetLoweringObjectFileWasm : public TargetLoweringObjectFile { bool shouldPutJumpTableInFunctionSection(bool UsesLabelDifference, const Function &F) const override; + MCSection *getNamedReadOnlySection(StringRef Name) const override; + void InitializeWasm(); MCSection *getStaticCtorSection(unsigned Priority, const MCSymbol *KeySym) const override; diff --git a/llvm/include/llvm/Target/TargetLoweringObjectFile.h b/llvm/include/llvm/Target/TargetLoweringObjectFile.h index 3cce5974e6705..df8dd3466451e 100644 --- a/llvm/include/llvm/Target/TargetLoweringObjectFile.h +++ b/llvm/include/llvm/Target/TargetLoweringObjectFile.h @@ -90,6 +90,13 @@ class LLVM_ABI TargetLoweringObjectFile : public MCObjectFileInfo { /// Emit the module-level metadata that the platform cares about. virtual void emitModuleMetadata(MCStreamer &Streamer, Module &M) const {} + /// Get a read-only data section with the given name, using format-appropriate + /// defaults. + /// Returns nullptr if not supported by this object file format. + virtual MCSection *getNamedReadOnlySection(StringRef Name) const { + return nullptr; + } + /// Emit Call Graph Profile metadata. void emitCGProfileMetadata(MCStreamer &Streamer, Module &M) const; diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 0580fc0f3a034..af48b444b7991 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2980,6 +2980,27 @@ bool AsmPrinter::doFinalization(Module &M) { TLOF.emitModuleMetadata(*OutStreamer, M); + // Emit raw section data from llvm.raw.sections metadata. + if (const NamedMDNode *RawSections = + M.getNamedMetadata("llvm.raw.sections")) { + for (const MDNode *Op : RawSections->operands()) { + assert(Op->getNumOperands() == 3 && + "llvm.raw.sections metadata entry must have three operands"); + auto *SectionName = cast<MDString>(Op->getOperand(0)); + auto *AlignCI = mdconst::extract<ConstantInt>(Op->getOperand(1)); + auto *Data = cast<MDString>(Op->getOperand(2)); + + if (MCSection *Section = + TLOF.getNamedReadOnlySection(SectionName->getString())) { + OutStreamer->pushSection(); + OutStreamer->switchSection(Section); + OutStreamer->emitValueToAlignment(Align(AlignCI->getZExtValue())); + OutStreamer->emitBytes(Data->getString()); + OutStreamer->popSection(); + } + } + } + if (Target.isOSBinFormatELF()) { MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>(); diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index 84b72321b1f55..bcdb2c3d63715 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -377,6 +377,11 @@ void TargetLoweringObjectFileELF::emitModuleMetadata(MCStreamer &Streamer, emitCGProfileMetadata(Streamer, M); } +MCSection * +TargetLoweringObjectFileELF::getNamedReadOnlySection(StringRef Name) const { + return getContext().getELFSection(Name, ELF::SHT_PROGBITS, ELF::SHF_ALLOC); +} + void TargetLoweringObjectFileELF::emitLinkerDirectives(MCStreamer &Streamer, Module &M) const { auto &C = getContext(); @@ -1350,6 +1355,13 @@ void TargetLoweringObjectFileMachO::emitModuleMetadata(MCStreamer &Streamer, Streamer.addBlankLine(); } +MCSection * +TargetLoweringObjectFileMachO::getNamedReadOnlySection(StringRef Name) const { + auto [Segment, SecName] = Name.split(','); + return getContext().getMachOSection(Segment, SecName, 0, + SectionKind::getReadOnly()); +} + void TargetLoweringObjectFileMachO::emitLinkerDirectives(MCStreamer &Streamer, Module &M) const { if (auto *LinkerOptions = M.getNamedMetadata("llvm.linker.options")) { @@ -1944,6 +1956,12 @@ void TargetLoweringObjectFileCOFF::emitModuleMetadata(MCStreamer &Streamer, }); } +MCSection * +TargetLoweringObjectFileCOFF::getNamedReadOnlySection(StringRef Name) const { + return getContext().getCOFFSection( + Name, COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ); +} + void TargetLoweringObjectFileCOFF::emitLinkerDirectives( MCStreamer &Streamer, Module &M) const { if (NamedMDNode *LinkerOptions = M.getNamedMetadata("llvm.linker.options")) { @@ -2258,6 +2276,11 @@ void TargetLoweringObjectFileWasm::getModuleMetadata(Module &M) { Used.insert(GO); } +MCSection * +TargetLoweringObjectFileWasm::getNamedReadOnlySection(StringRef Name) const { + return getContext().getWasmSection(Name, SectionKind::getReadOnly()); +} + MCSection *TargetLoweringObjectFileWasm::getExplicitSectionGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { // We don't support explict section names for functions in the wasm object diff --git a/llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll b/llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll new file mode 100644 index 0000000000000..a326a5e912508 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll @@ -0,0 +1,7 @@ +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown %s -o %t.o +; RUN: llvm-readobj --sections %t.o | FileCheck %s + +; CHECK: Name: __clangast + +!0 = !{!"__clangast", i32 8, !"\de\ad\be\ef"} +!llvm.raw.sections = !{!0} diff --git a/llvm/test/CodeGen/X86/raw-sections-coff.ll b/llvm/test/CodeGen/X86/raw-sections-coff.ll new file mode 100644 index 0000000000000..fc9d2e7515f94 --- /dev/null +++ b/llvm/test/CodeGen/X86/raw-sections-coff.ll @@ -0,0 +1,12 @@ +; RUN: llc -filetype=obj -mtriple=x86_64-windows-msvc %s -o %t.o +; RUN: llvm-readobj --sections %t.o | FileCheck %s + +; CHECK: Name: clangast +; CHECK: RawDataSize: +; CHECK: Characteristics [ +; CHECK-DAG: IMAGE_SCN_CNT_INITIALIZED_DATA +; CHECK-DAG: IMAGE_SCN_MEM_READ +; CHECK: ] + +!0 = !{!"clangast", i32 8, !"\de\ad\be\ef"} +!llvm.raw.sections = !{!0} diff --git a/llvm/test/CodeGen/X86/raw-sections-elf.ll b/llvm/test/CodeGen/X86/raw-sections-elf.ll new file mode 100644 index 0000000000000..c1afbb043066b --- /dev/null +++ b/llvm/test/CodeGen/X86/raw-sections-elf.ll @@ -0,0 +1,7 @@ +; RUN: llc -filetype=obj -mtriple=x86_64-linux-gnu %s -o %t.o +; RUN: llvm-readelf --sections %t.o | FileCheck %s + +; CHECK: __clangast PROGBITS {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} 00 A 0 0 8 + +!0 = !{!"__clangast", i32 8, !"\de\ad\be\ef"} +!llvm.raw.sections = !{!0} diff --git a/llvm/test/CodeGen/X86/raw-sections-macho.ll b/llvm/test/CodeGen/X86/raw-sections-macho.ll new file mode 100644 index 0000000000000..54d16b45529c4 --- /dev/null +++ b/llvm/test/CodeGen/X86/raw-sections-macho.ll @@ -0,0 +1,9 @@ +; RUN: llc -filetype=obj -mtriple=x86_64-apple-darwin %s -o %t.o +; RUN: llvm-readobj --sections %t.o | FileCheck %s + +; CHECK: Name: __clangast +; CHECK-NEXT: Segment: __CLANG +; CHECK: Size: + +!0 = !{!"__CLANG,__clangast", i32 8, !"\de\ad\be\ef"} +!llvm.raw.sections = !{!0} >From 139c6119893b9bc991feff84a9394cadff8bcd5a Mon Sep 17 00:00:00 2001 From: Steffen Holst Larsen <[email protected]> Date: Wed, 5 Aug 2026 04:09:58 -0500 Subject: [PATCH 2/5] Fix test expectations Signed-off-by: Steffen Holst Larsen <[email protected]> --- clang/test/Modules/gmodules-nodebug.cpp | 1 + clang/test/Modules/lsv-debuginfo.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/clang/test/Modules/gmodules-nodebug.cpp b/clang/test/Modules/gmodules-nodebug.cpp index d83103768e838..da05d35667d52 100644 --- a/clang/test/Modules/gmodules-nodebug.cpp +++ b/clang/test/Modules/gmodules-nodebug.cpp @@ -12,3 +12,4 @@ __void_t<> func() {} // CHECK: !DICompileUnit // CHECK-NOT: __void_t +// CHECK: !{!"__clangast", diff --git a/clang/test/Modules/lsv-debuginfo.cpp b/clang/test/Modules/lsv-debuginfo.cpp index 61d2ff9514ed3..fc05fce5c6d5d 100644 --- a/clang/test/Modules/lsv-debuginfo.cpp +++ b/clang/test/Modules/lsv-debuginfo.cpp @@ -24,20 +24,20 @@ // CHECK: !llvm.raw.sections = !{[[ADT_SEC:![0-9]+]]} // CHECK: [[ADT_SEC]] = !{!"__clangast", -// B +// B — named metadata first, then numbered nodes (DICompositeType before blob) // CHECK: !llvm.raw.sections = !{[[B_SEC:![0-9]+]]} -// CHECK: [[B_SEC]] = !{!"__clangast", // This type isn't anchored anywhere, expect a full definition. // CHECK: !DICompositeType({{.*}}, name: "AlignedCharArray<4U, 16U>", // CHECK-SAME: elements: +// CHECK: [[B_SEC]] = !{!"__clangast", -// C +// C — same ordering // CHECK: !llvm.raw.sections = !{[[C_SEC:![0-9]+]]} -// CHECK: [[C_SEC]] = !{!"__clangast", // Here, too. // CHECK: !DICompositeType({{.*}}, name: "AlignedCharArray<4U, 16U>", // CHECK-SAME: elements: +// CHECK: [[C_SEC]] = !{!"__clangast", #include <B/B.h> >From 8f0d295f95cc9887d7909b65d543137f51e283a4 Mon Sep 17 00:00:00 2001 From: Steffen Holst Larsen <[email protected]> Date: Wed, 5 Aug 2026 06:26:02 -0500 Subject: [PATCH 3/5] Change expectations to be target-independent Signed-off-by: Steffen Holst Larsen <[email protected]> --- clang/test/Modules/gmodules-nodebug.cpp | 2 +- clang/test/Modules/lsv-debuginfo.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/test/Modules/gmodules-nodebug.cpp b/clang/test/Modules/gmodules-nodebug.cpp index da05d35667d52..1be0dddfa149b 100644 --- a/clang/test/Modules/gmodules-nodebug.cpp +++ b/clang/test/Modules/gmodules-nodebug.cpp @@ -12,4 +12,4 @@ __void_t<> func() {} // CHECK: !DICompileUnit // CHECK-NOT: __void_t -// CHECK: !{!"__clangast", +// CHECK: !{!"{{(__CLANG,)?(__)?}}clangast", diff --git a/clang/test/Modules/lsv-debuginfo.cpp b/clang/test/Modules/lsv-debuginfo.cpp index fc05fce5c6d5d..189266f4ae324 100644 --- a/clang/test/Modules/lsv-debuginfo.cpp +++ b/clang/test/Modules/lsv-debuginfo.cpp @@ -22,22 +22,22 @@ // ADT // CHECK: !llvm.raw.sections = !{[[ADT_SEC:![0-9]+]]} -// CHECK: [[ADT_SEC]] = !{!"__clangast", +// CHECK: [[ADT_SEC]] = !{!"{{(__CLANG,)?(__)?}}clangast", -// B — named metadata first, then numbered nodes (DICompositeType before blob) +// B // CHECK: !llvm.raw.sections = !{[[B_SEC:![0-9]+]]} // This type isn't anchored anywhere, expect a full definition. // CHECK: !DICompositeType({{.*}}, name: "AlignedCharArray<4U, 16U>", // CHECK-SAME: elements: -// CHECK: [[B_SEC]] = !{!"__clangast", +// CHECK: [[B_SEC]] = !{!"{{(__CLANG,)?(__)?}}clangast", -// C — same ordering +// C // CHECK: !llvm.raw.sections = !{[[C_SEC:![0-9]+]]} // Here, too. // CHECK: !DICompositeType({{.*}}, name: "AlignedCharArray<4U, 16U>", // CHECK-SAME: elements: -// CHECK: [[C_SEC]] = !{!"__clangast", +// CHECK: [[C_SEC]] = !{!"{{(__CLANG,)?(__)?}}clangast", #include <B/B.h> >From db80d8641bdd74f5376ff8f6b1f473a2b093c299 Mon Sep 17 00:00:00 2001 From: Steffen Holst Larsen <[email protected]> Date: Thu, 6 Aug 2026 01:34:09 -0500 Subject: [PATCH 4/5] Add section kind field, verify in verifier and document Signed-off-by: Steffen Holst Larsen <[email protected]> --- .../CodeGen/ObjectFilePCHContainerWriter.cpp | 7 +++-- llvm/docs/LangRef.md | 29 +++++++++++++++++ .../CodeGen/TargetLoweringObjectFileImpl.h | 8 ++--- llvm/include/llvm/MC/SectionKind.h | 5 +++ .../llvm/Target/TargetLoweringObjectFile.h | 6 ++-- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 11 ++++--- .../CodeGen/TargetLoweringObjectFileImpl.cpp | 30 ++++++++++-------- llvm/lib/IR/Verifier.cpp | 31 +++++++++++++++++++ .../CodeGen/WebAssembly/raw-sections-wasm.ll | 2 +- llvm/test/CodeGen/X86/raw-sections-coff.ll | 2 +- llvm/test/CodeGen/X86/raw-sections-elf.ll | 2 +- llvm/test/CodeGen/X86/raw-sections-macho.ll | 2 +- llvm/test/Verifier/raw-sections.ll | 9 ++++++ 13 files changed, 113 insertions(+), 31 deletions(-) create mode 100644 llvm/test/Verifier/raw-sections.ll diff --git a/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp b/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp index 3a507782bb66e..fffc28721e825 100644 --- a/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp +++ b/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp @@ -25,6 +25,7 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/MC/SectionKind.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Object/COFF.h" #include "llvm/Support/Path.h" @@ -311,10 +312,12 @@ class PCHContainerGenerator : public ASTConsumer { else SectionName = "__clangast"; + auto *Int32Ty = llvm::Type::getInt32Ty(*VMContext); llvm::Metadata *Ops[] = { llvm::MDString::get(*VMContext, SectionName), - llvm::ConstantAsMetadata::get( - llvm::ConstantInt::get(llvm::Type::getInt32Ty(*VMContext), 8)), + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int32Ty, 8)), + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( + Int32Ty, llvm::SectionKind::getReadOnly().getValue())), llvm::MDString::get(*VMContext, StringRef(SerializedAST.data(), Size))}; RawSections->addOperand(llvm::MDTuple::get(*VMContext, Ops)); diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md index 6a3194271b838..bd484213eff73 100644 --- a/llvm/docs/LangRef.md +++ b/llvm/docs/LangRef.md @@ -9623,6 +9623,35 @@ for an integer access: Multiple TBAA operands are allowed to support merging of modules that may use different TBAA hierarchies (e.g., when mixing C and C++). +## '`llvm.raw.sections`' Named Metadata + +The module-level `!llvm.raw.sections` metadata allows embedding arbitrary +binary data into named sections of the output object file. A +`!llvm.raw.sections` metadata node is a list of metadata nodes with the +following fields: + +``` +!0 = !{!"section_name", i32 alignment, i32 section_kind, !"raw data"} +``` + +- **section_name**: The name of the output section. +- **alignment**: The byte alignment of the section data. +- **section_kind**: An integer value corresponding to the `SectionKind` type + declared in the `<include/llvm/MC/SectionKind.h>` header file. This field + specifies the nature of the section (e.g. read-only, data, metadata). Each + target maps this to format-appropriate section flags. +- **raw data**: The binary contents of the section. + +Example: +``` +!llvm.raw.sections = !{!0} +!0 = !{!"__mydata", i32 8, i32 4, !"\DE\AD\BE\EF"} +``` + +Each of the nodes inside a `!llvm.raw.sections` metadata node gets lowered to +a target-specific named data section. Targets that do not support arbitrary +named sections silently skip `!llvm.raw.sections` metadata nodes. + (summary)= ## ThinLTO Summary diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h index a56e8ed6e0879..f334e5e454454 100644 --- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -49,7 +49,7 @@ class LLVM_ABI TargetLoweringObjectFileELF : public TargetLoweringObjectFile { /// Emit Obj-C garbage collection and linker options. void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override; - MCSection *getNamedReadOnlySection(StringRef Name) const override; + MCSection *getNamedSection(StringRef Name, SectionKind Kind) const override; void emitPersonalityValue(MCStreamer &Streamer, const DataLayout &DL, const MCSymbol *Sym, @@ -146,7 +146,7 @@ class LLVM_ABI TargetLoweringObjectFileMachO : public TargetLoweringObjectFile { /// Emit the module flags that specify the garbage collection information. void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override; - MCSection *getNamedReadOnlySection(StringRef Name) const override; + MCSection *getNamedSection(StringRef Name, SectionKind Kind) const override; void emitLinkerDirectives(MCStreamer &Streamer, Module &M) const override; @@ -211,7 +211,7 @@ class LLVM_ABI TargetLoweringObjectFileCOFF : public TargetLoweringObjectFile { /// Emit Obj-C garbage collection and linker options. void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override; - MCSection *getNamedReadOnlySection(StringRef Name) const override; + MCSection *getNamedSection(StringRef Name, SectionKind Kind) const override; void emitLinkerDirectives(MCStreamer &Streamer, Module &M) const override; @@ -251,7 +251,7 @@ class LLVM_ABI TargetLoweringObjectFileWasm : public TargetLoweringObjectFile { bool shouldPutJumpTableInFunctionSection(bool UsesLabelDifference, const Function &F) const override; - MCSection *getNamedReadOnlySection(StringRef Name) const override; + MCSection *getNamedSection(StringRef Name, SectionKind Kind) const override; void InitializeWasm(); MCSection *getStaticCtorSection(unsigned Priority, diff --git a/llvm/include/llvm/MC/SectionKind.h b/llvm/include/llvm/MC/SectionKind.h index 61e400fe9edee..5c10f8f25d64d 100644 --- a/llvm/include/llvm/MC/SectionKind.h +++ b/llvm/include/llvm/MC/SectionKind.h @@ -212,6 +212,11 @@ class SectionKind { static SectionKind getCommon() { return get(Common); } static SectionKind getData() { return get(Data); } static SectionKind getReadOnlyWithRel() { return get(ReadOnlyWithRel); } + + unsigned getValue() const { return static_cast<unsigned>(K); } + static SectionKind fromValue(unsigned Val) { + return get(static_cast<Kind>(Val)); + } }; } // end namespace llvm diff --git a/llvm/include/llvm/Target/TargetLoweringObjectFile.h b/llvm/include/llvm/Target/TargetLoweringObjectFile.h index df8dd3466451e..437279501af53 100644 --- a/llvm/include/llvm/Target/TargetLoweringObjectFile.h +++ b/llvm/include/llvm/Target/TargetLoweringObjectFile.h @@ -90,10 +90,10 @@ class LLVM_ABI TargetLoweringObjectFile : public MCObjectFileInfo { /// Emit the module-level metadata that the platform cares about. virtual void emitModuleMetadata(MCStreamer &Streamer, Module &M) const {} - /// Get a read-only data section with the given name, using format-appropriate - /// defaults. + /// Get a section with the given name and kind, using format-appropriate + /// defaults for section flags. /// Returns nullptr if not supported by this object file format. - virtual MCSection *getNamedReadOnlySection(StringRef Name) const { + virtual MCSection *getNamedSection(StringRef Name, SectionKind Kind) const { return nullptr; } diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index af48b444b7991..febedf3b49a41 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2980,18 +2980,19 @@ bool AsmPrinter::doFinalization(Module &M) { TLOF.emitModuleMetadata(*OutStreamer, M); - // Emit raw section data from llvm.raw.sections metadata. + // Emit raw section data from llvm.raw.sections metadata. Each operand is + // a tuple of {section_name, alignment, section_kind, data}. if (const NamedMDNode *RawSections = M.getNamedMetadata("llvm.raw.sections")) { for (const MDNode *Op : RawSections->operands()) { - assert(Op->getNumOperands() == 3 && - "llvm.raw.sections metadata entry must have three operands"); auto *SectionName = cast<MDString>(Op->getOperand(0)); auto *AlignCI = mdconst::extract<ConstantInt>(Op->getOperand(1)); - auto *Data = cast<MDString>(Op->getOperand(2)); + auto *KindCI = mdconst::extract<ConstantInt>(Op->getOperand(2)); + auto *Data = cast<MDString>(Op->getOperand(3)); + SectionKind Kind = SectionKind::fromValue(KindCI->getZExtValue()); if (MCSection *Section = - TLOF.getNamedReadOnlySection(SectionName->getString())) { + TLOF.getNamedSection(SectionName->getString(), Kind)) { OutStreamer->pushSection(); OutStreamer->switchSection(Section); OutStreamer->emitValueToAlignment(Align(AlignCI->getZExtValue())); diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index bcdb2c3d63715..df87c8bdbda10 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -377,11 +377,6 @@ void TargetLoweringObjectFileELF::emitModuleMetadata(MCStreamer &Streamer, emitCGProfileMetadata(Streamer, M); } -MCSection * -TargetLoweringObjectFileELF::getNamedReadOnlySection(StringRef Name) const { - return getContext().getELFSection(Name, ELF::SHT_PROGBITS, ELF::SHF_ALLOC); -} - void TargetLoweringObjectFileELF::emitLinkerDirectives(MCStreamer &Streamer, Module &M) const { auto &C = getContext(); @@ -576,6 +571,14 @@ static unsigned getELFSectionFlags(SectionKind K, const Triple &T) { return Flags; } +MCSection * +TargetLoweringObjectFileELF::getNamedSection(StringRef Name, + SectionKind Kind) const { + unsigned Type = getELFSectionType(Name, Kind); + unsigned Flags = getELFSectionFlags(Kind, getContext().getTargetTriple()); + return getContext().getELFSection(Name, Type, Flags); +} + static const Comdat *getELFComdat(const GlobalValue *GV) { const Comdat *C = GV->getComdat(); if (!C) @@ -1356,10 +1359,10 @@ void TargetLoweringObjectFileMachO::emitModuleMetadata(MCStreamer &Streamer, } MCSection * -TargetLoweringObjectFileMachO::getNamedReadOnlySection(StringRef Name) const { +TargetLoweringObjectFileMachO::getNamedSection(StringRef Name, + SectionKind Kind) const { auto [Segment, SecName] = Name.split(','); - return getContext().getMachOSection(Segment, SecName, 0, - SectionKind::getReadOnly()); + return getContext().getMachOSection(Segment, SecName, 0, Kind); } void TargetLoweringObjectFileMachO::emitLinkerDirectives(MCStreamer &Streamer, @@ -1957,9 +1960,9 @@ void TargetLoweringObjectFileCOFF::emitModuleMetadata(MCStreamer &Streamer, } MCSection * -TargetLoweringObjectFileCOFF::getNamedReadOnlySection(StringRef Name) const { - return getContext().getCOFFSection( - Name, COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ); +TargetLoweringObjectFileCOFF::getNamedSection(StringRef Name, + SectionKind Kind) const { + return getContext().getCOFFSection(Name, getCOFFSectionFlags(Kind, *TM)); } void TargetLoweringObjectFileCOFF::emitLinkerDirectives( @@ -2277,8 +2280,9 @@ void TargetLoweringObjectFileWasm::getModuleMetadata(Module &M) { } MCSection * -TargetLoweringObjectFileWasm::getNamedReadOnlySection(StringRef Name) const { - return getContext().getWasmSection(Name, SectionKind::getReadOnly()); +TargetLoweringObjectFileWasm::getNamedSection(StringRef Name, + SectionKind Kind) const { + return getContext().getWasmSection(Name, Kind); } MCSection *TargetLoweringObjectFileWasm::getExplicitSectionGlobal( diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 44d1843aa56a9..e5ec2ac833338 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -308,6 +308,7 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport { visitModuleIdents(); visitModuleCommandLines(); visitModuleErrnoTBAA(); + visitModuleRawSections(); verifyCompileUnits(); @@ -345,6 +346,7 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport { void visitModuleIdents(); void visitModuleCommandLines(); void visitModuleErrnoTBAA(); + void visitModuleRawSections(); void visitModuleFlags(); void visitModuleFlag(const MDNode *Op, DenseMap<const MDString *, const MDNode *> &SeenIDs, @@ -1844,6 +1846,35 @@ void Verifier::visitModuleErrnoTBAA() { TBAAVerifyHelper.visitTBAAMetadata(nullptr, N); } +void Verifier::visitModuleRawSections() { + const NamedMDNode *RawSections = M.getNamedMetadata("llvm.raw.sections"); + if (!RawSections) + return; + + for (const MDNode *N : RawSections->operands()) { + if (N->getNumOperands() != 4) { + CheckFailed("llvm.raw.sections entry must have four operands", N); + continue; + } + Check(dyn_cast_or_null<MDString>(N->getOperand(0)), + "llvm.raw.sections entry operand 0 must be a string " + "(section name)", + N); + Check(mdconst::dyn_extract_or_null<ConstantInt>(N->getOperand(1)), + "llvm.raw.sections entry operand 1 must be an integer " + "(alignment)", + N); + Check(mdconst::dyn_extract_or_null<ConstantInt>(N->getOperand(2)), + "llvm.raw.sections entry operand 2 must be an integer " + "(section kind)", + N); + Check(dyn_cast_or_null<MDString>(N->getOperand(3)), + "llvm.raw.sections entry operand 3 must be a string " + "(section data)", + N); + } +} + void Verifier::visitModuleFlags() { const NamedMDNode *Flags = M.getModuleFlagsMetadata(); if (!Flags) return; diff --git a/llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll b/llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll index a326a5e912508..8bcad587a0e01 100644 --- a/llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll +++ b/llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll @@ -3,5 +3,5 @@ ; CHECK: Name: __clangast -!0 = !{!"__clangast", i32 8, !"\de\ad\be\ef"} +!0 = !{!"__clangast", i32 8, i32 4, !"\de\ad\be\ef"} !llvm.raw.sections = !{!0} diff --git a/llvm/test/CodeGen/X86/raw-sections-coff.ll b/llvm/test/CodeGen/X86/raw-sections-coff.ll index fc9d2e7515f94..4b83e5145a422 100644 --- a/llvm/test/CodeGen/X86/raw-sections-coff.ll +++ b/llvm/test/CodeGen/X86/raw-sections-coff.ll @@ -8,5 +8,5 @@ ; CHECK-DAG: IMAGE_SCN_MEM_READ ; CHECK: ] -!0 = !{!"clangast", i32 8, !"\de\ad\be\ef"} +!0 = !{!"clangast", i32 8, i32 4, !"\de\ad\be\ef"} !llvm.raw.sections = !{!0} diff --git a/llvm/test/CodeGen/X86/raw-sections-elf.ll b/llvm/test/CodeGen/X86/raw-sections-elf.ll index c1afbb043066b..8ac065224ce9a 100644 --- a/llvm/test/CodeGen/X86/raw-sections-elf.ll +++ b/llvm/test/CodeGen/X86/raw-sections-elf.ll @@ -3,5 +3,5 @@ ; CHECK: __clangast PROGBITS {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} 00 A 0 0 8 -!0 = !{!"__clangast", i32 8, !"\de\ad\be\ef"} +!0 = !{!"__clangast", i32 8, i32 4, !"\de\ad\be\ef"} !llvm.raw.sections = !{!0} diff --git a/llvm/test/CodeGen/X86/raw-sections-macho.ll b/llvm/test/CodeGen/X86/raw-sections-macho.ll index 54d16b45529c4..cff3272c9ad83 100644 --- a/llvm/test/CodeGen/X86/raw-sections-macho.ll +++ b/llvm/test/CodeGen/X86/raw-sections-macho.ll @@ -5,5 +5,5 @@ ; CHECK-NEXT: Segment: __CLANG ; CHECK: Size: -!0 = !{!"__CLANG,__clangast", i32 8, !"\de\ad\be\ef"} +!0 = !{!"__CLANG,__clangast", i32 8, i32 4, !"\de\ad\be\ef"} !llvm.raw.sections = !{!0} diff --git a/llvm/test/Verifier/raw-sections.ll b/llvm/test/Verifier/raw-sections.ll new file mode 100644 index 0000000000000..77bc01f89b06c --- /dev/null +++ b/llvm/test/Verifier/raw-sections.ll @@ -0,0 +1,9 @@ +; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s + +; CHECK: llvm.raw.sections entry must have four operands +; CHECK: llvm.raw.sections entry operand 0 must be a string (section name) + +!llvm.raw.sections = !{!0, !1, !2} +!0 = !{!"__clangast", i32 8, i32 4, !"data"} +!1 = !{!"__clangast", i32 8, !"data"} +!2 = !{i32 0, i32 8, i32 4, !"data"} >From 6531036a48b8c230362fe4321cafd8311e2980a8 Mon Sep 17 00:00:00 2001 From: Steffen Holst Larsen <[email protected]> Date: Mon, 10 Aug 2026 03:36:46 -0500 Subject: [PATCH 5/5] Switch to a new section flag to avoid SectionKind layout dependence Signed-off-by: Steffen Holst Larsen <[email protected]> --- .../CodeGen/ObjectFilePCHContainerWriter.cpp | 5 +-- llvm/docs/LangRef.md | 39 ++++++++++++++++--- llvm/include/llvm/IR/Module.h | 24 ++++++++++++ llvm/include/llvm/MC/SectionKind.h | 5 --- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 24 ++++++++++-- llvm/lib/IR/Module.cpp | 21 ++++++++++ llvm/lib/IR/Verifier.cpp | 11 +++++- .../CodeGen/WebAssembly/raw-sections-wasm.ll | 2 +- llvm/test/CodeGen/X86/raw-sections-coff.ll | 2 +- llvm/test/CodeGen/X86/raw-sections-elf.ll | 2 +- llvm/test/CodeGen/X86/raw-sections-macho.ll | 2 +- llvm/test/Verifier/raw-sections-flags.ll | 31 +++++++++++++++ llvm/test/Verifier/raw-sections.ll | 4 +- 13 files changed, 147 insertions(+), 25 deletions(-) create mode 100644 llvm/test/Verifier/raw-sections-flags.ll diff --git a/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp b/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp index fffc28721e825..6b71448142724 100644 --- a/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp +++ b/clang/lib/CodeGen/ObjectFilePCHContainerWriter.cpp @@ -25,7 +25,6 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" -#include "llvm/MC/SectionKind.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Object/COFF.h" #include "llvm/Support/Path.h" @@ -316,8 +315,8 @@ class PCHContainerGenerator : public ASTConsumer { llvm::Metadata *Ops[] = { llvm::MDString::get(*VMContext, SectionName), llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int32Ty, 8)), - llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( - Int32Ty, llvm::SectionKind::getReadOnly().getValue())), + llvm::ConstantAsMetadata::get( + llvm::ConstantInt::get(Int32Ty, llvm::Module::RawSectionAlloc)), llvm::MDString::get(*VMContext, StringRef(SerializedAST.data(), Size))}; RawSections->addOperand(llvm::MDTuple::get(*VMContext, Ops)); diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md index bd484213eff73..ec4b1dbd3a593 100644 --- a/llvm/docs/LangRef.md +++ b/llvm/docs/LangRef.md @@ -9631,21 +9631,48 @@ binary data into named sections of the output object file. A following fields: ``` -!0 = !{!"section_name", i32 alignment, i32 section_kind, !"raw data"} +!0 = !{!"section_name", i32 alignment, i32 flags, !"raw data"} ``` - **section_name**: The name of the output section. - **alignment**: The byte alignment of the section data. -- **section_kind**: An integer value corresponding to the `SectionKind` type - declared in the `<include/llvm/MC/SectionKind.h>` header file. This field - specifies the nature of the section (e.g. read-only, data, metadata). Each - target maps this to format-appropriate section flags. +- **flags**: A bitmask describing the properties of the section. Each target + maps this onto format-appropriate section flags. The supported bits are + listed below. - **raw data**: The binary contents of the section. +```{list-table} +:header-rows: 1 + +* - Value + - Name + - Description + +* - `0x1` + - Alloc + - The section occupies memory at load time. + +* - `0x2` + - Write + - The section is writable. Requires `Alloc`. + +* - `0x4` + - Exec + - The section is executable. Requires `Alloc`. + +* - `0x8` + - Exclude + - The section is dropped from the final link. Must not be combined with any + other bit. +``` + +A flags value of `0` describes a section that is present in the object file +but is not loaded into memory. `Write` and `Exec` must not be combined. + Example: ``` !llvm.raw.sections = !{!0} -!0 = !{!"__mydata", i32 8, i32 4, !"\DE\AD\BE\EF"} +!0 = !{!"__mydata", i32 8, i32 1, !"\DE\AD\BE\EF"} ``` Each of the nodes inside a `!llvm.raw.sections` metadata node gets lowered to diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h index 16dad6ad446fb..fa061f9e8ef1f 100644 --- a/llvm/include/llvm/IR/Module.h +++ b/llvm/include/llvm/IR/Module.h @@ -160,6 +160,30 @@ class LLVM_ABI Module { /// converted result in MFB. static bool isValidModFlagBehavior(Metadata *MD, ModFlagBehavior &MFB); + /// Flags describing the properties of a section declared via the + /// `llvm.raw.sections` named metadata. Targets map these onto + /// format-specific section flags. + enum RawSectionFlags { + /// The section occupies memory at load time. + RawSectionAlloc = 1 << 0, + + /// The section is writable at runtime. Requires RawSectionAlloc. + RawSectionWrite = 1 << 1, + + /// The section is executable. Requires RawSectionAlloc. + RawSectionExec = 1 << 2, + + /// The section is excluded from the final link. Must not be combined + /// with any other flag. + RawSectionExclude = 1 << 3, + + RawSectionFlagsMask = + RawSectionAlloc | RawSectionWrite | RawSectionExec | RawSectionExclude + }; + + /// Checks whether \p Flags is a valid combination of RawSectionFlags. + static bool isValidRawSectionFlags(uint64_t Flags); + struct ModuleFlagEntry { ModFlagBehavior Behavior; MDString *Key; diff --git a/llvm/include/llvm/MC/SectionKind.h b/llvm/include/llvm/MC/SectionKind.h index 5c10f8f25d64d..61e400fe9edee 100644 --- a/llvm/include/llvm/MC/SectionKind.h +++ b/llvm/include/llvm/MC/SectionKind.h @@ -212,11 +212,6 @@ class SectionKind { static SectionKind getCommon() { return get(Common); } static SectionKind getData() { return get(Data); } static SectionKind getReadOnlyWithRel() { return get(ReadOnlyWithRel); } - - unsigned getValue() const { return static_cast<unsigned>(K); } - static SectionKind fromValue(unsigned Val) { - return get(static_cast<Kind>(Val)); - } }; } // end namespace llvm diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index febedf3b49a41..acf5fb8a1cbba 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2902,6 +2902,24 @@ static void removeMemtagFromGlobal(GlobalVariable &G) { G.setSanitizerMetadata(Meta); } +/// Map the target-independent flags of an `llvm.raw.sections` entry onto the +/// SectionKind that targets use to derive format-specific section flags. +/// The flag combination is validated by the IR verifier. +static SectionKind getKindForRawSectionFlags(uint64_t Flags) { + assert(Module::isValidRawSectionFlags(Flags) && + "invalid llvm.raw.sections flags should be rejected by the verifier"); + + if (Flags & Module::RawSectionExclude) + return SectionKind::getExclude(); + if (!(Flags & Module::RawSectionAlloc)) + return SectionKind::getMetadata(); + if (Flags & Module::RawSectionExec) + return SectionKind::getText(); + if (Flags & Module::RawSectionWrite) + return SectionKind::getData(); + return SectionKind::getReadOnly(); +} + bool AsmPrinter::doFinalization(Module &M) { // Set the MachineFunction to nullptr so that we can catch attempted // accesses to MF specific features at the module level and so that @@ -2981,16 +2999,16 @@ bool AsmPrinter::doFinalization(Module &M) { TLOF.emitModuleMetadata(*OutStreamer, M); // Emit raw section data from llvm.raw.sections metadata. Each operand is - // a tuple of {section_name, alignment, section_kind, data}. + // a tuple of {section_name, alignment, flags, data}. if (const NamedMDNode *RawSections = M.getNamedMetadata("llvm.raw.sections")) { for (const MDNode *Op : RawSections->operands()) { auto *SectionName = cast<MDString>(Op->getOperand(0)); auto *AlignCI = mdconst::extract<ConstantInt>(Op->getOperand(1)); - auto *KindCI = mdconst::extract<ConstantInt>(Op->getOperand(2)); + auto *FlagsCI = mdconst::extract<ConstantInt>(Op->getOperand(2)); auto *Data = cast<MDString>(Op->getOperand(3)); - SectionKind Kind = SectionKind::fromValue(KindCI->getZExtValue()); + SectionKind Kind = getKindForRawSectionFlags(FlagsCI->getZExtValue()); if (MCSection *Section = TLOF.getNamedSection(SectionName->getString(), Kind)) { OutStreamer->pushSection(); diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp index 3dcc9ec5dac3f..52adf4f639a36 100644 --- a/llvm/lib/IR/Module.cpp +++ b/llvm/lib/IR/Module.cpp @@ -337,6 +337,27 @@ bool Module::isValidModFlagBehavior(Metadata *MD, ModFlagBehavior &MFB) { return false; } +bool Module::isValidRawSectionFlags(uint64_t Flags) { + if (Flags & ~static_cast<uint64_t>(RawSectionFlagsMask)) + return false; + + // An excluded section is not present in the output, so it cannot also be + // allocated, written or executed. + if (Flags & RawSectionExclude) + return Flags == RawSectionExclude; + + // Only an allocated section can be written to or executed. + if ((Flags & (RawSectionWrite | RawSectionExec)) && + !(Flags & RawSectionAlloc)) + return false; + + // No section format represents writable executable data. + if ((Flags & RawSectionWrite) && (Flags & RawSectionExec)) + return false; + + return true; +} + /// getModuleFlagsMetadata - Returns the module flags in the provided vector. void Module:: getModuleFlagsMetadata(SmallVectorImpl<ModuleFlagEntry> &Flags) const { diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index e5ec2ac833338..83c73dcc6defe 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1864,10 +1864,17 @@ void Verifier::visitModuleRawSections() { "llvm.raw.sections entry operand 1 must be an integer " "(alignment)", N); - Check(mdconst::dyn_extract_or_null<ConstantInt>(N->getOperand(2)), + auto *FlagsCI = mdconst::dyn_extract_or_null<ConstantInt>(N->getOperand(2)); + Check(FlagsCI, "llvm.raw.sections entry operand 2 must be an integer " - "(section kind)", + "(flags)", N); + if (!Module::isValidRawSectionFlags(FlagsCI->getZExtValue())) { + CheckFailed("llvm.raw.sections entry operand 2 is not a valid " + "combination of section flags", + N); + continue; + } Check(dyn_cast_or_null<MDString>(N->getOperand(3)), "llvm.raw.sections entry operand 3 must be a string " "(section data)", diff --git a/llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll b/llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll index 8bcad587a0e01..166e5dc8b64e3 100644 --- a/llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll +++ b/llvm/test/CodeGen/WebAssembly/raw-sections-wasm.ll @@ -3,5 +3,5 @@ ; CHECK: Name: __clangast -!0 = !{!"__clangast", i32 8, i32 4, !"\de\ad\be\ef"} +!0 = !{!"__clangast", i32 8, i32 1, !"\de\ad\be\ef"} !llvm.raw.sections = !{!0} diff --git a/llvm/test/CodeGen/X86/raw-sections-coff.ll b/llvm/test/CodeGen/X86/raw-sections-coff.ll index 4b83e5145a422..28b59d516ca3e 100644 --- a/llvm/test/CodeGen/X86/raw-sections-coff.ll +++ b/llvm/test/CodeGen/X86/raw-sections-coff.ll @@ -8,5 +8,5 @@ ; CHECK-DAG: IMAGE_SCN_MEM_READ ; CHECK: ] -!0 = !{!"clangast", i32 8, i32 4, !"\de\ad\be\ef"} +!0 = !{!"clangast", i32 8, i32 1, !"\de\ad\be\ef"} !llvm.raw.sections = !{!0} diff --git a/llvm/test/CodeGen/X86/raw-sections-elf.ll b/llvm/test/CodeGen/X86/raw-sections-elf.ll index 8ac065224ce9a..a1264e05b1b85 100644 --- a/llvm/test/CodeGen/X86/raw-sections-elf.ll +++ b/llvm/test/CodeGen/X86/raw-sections-elf.ll @@ -3,5 +3,5 @@ ; CHECK: __clangast PROGBITS {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} 00 A 0 0 8 -!0 = !{!"__clangast", i32 8, i32 4, !"\de\ad\be\ef"} +!0 = !{!"__clangast", i32 8, i32 1, !"\de\ad\be\ef"} !llvm.raw.sections = !{!0} diff --git a/llvm/test/CodeGen/X86/raw-sections-macho.ll b/llvm/test/CodeGen/X86/raw-sections-macho.ll index cff3272c9ad83..46f15bf726ae0 100644 --- a/llvm/test/CodeGen/X86/raw-sections-macho.ll +++ b/llvm/test/CodeGen/X86/raw-sections-macho.ll @@ -5,5 +5,5 @@ ; CHECK-NEXT: Segment: __CLANG ; CHECK: Size: -!0 = !{!"__CLANG,__clangast", i32 8, i32 4, !"\de\ad\be\ef"} +!0 = !{!"__CLANG,__clangast", i32 8, i32 1, !"\de\ad\be\ef"} !llvm.raw.sections = !{!0} diff --git a/llvm/test/Verifier/raw-sections-flags.ll b/llvm/test/Verifier/raw-sections-flags.ll new file mode 100644 index 0000000000000..90a61259a3adb --- /dev/null +++ b/llvm/test/Verifier/raw-sections-flags.ll @@ -0,0 +1,31 @@ +; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s + +; Write without Alloc. +; CHECK: llvm.raw.sections entry operand 2 is not a valid combination of section flags +; CHECK-NEXT: !{!"__mydata", i32 8, i32 2, !"data"} + +; Exec without Alloc. +; CHECK: llvm.raw.sections entry operand 2 is not a valid combination of section flags +; CHECK-NEXT: !{!"__mydata", i32 8, i32 4, !"data"} + +; Write combined with Exec. +; CHECK: llvm.raw.sections entry operand 2 is not a valid combination of section flags +; CHECK-NEXT: !{!"__mydata", i32 8, i32 7, !"data"} + +; Exclude combined with Alloc. +; CHECK: llvm.raw.sections entry operand 2 is not a valid combination of section flags +; CHECK-NEXT: !{!"__mydata", i32 8, i32 9, !"data"} + +; Unknown flag bit. +; CHECK: llvm.raw.sections entry operand 2 is not a valid combination of section flags +; CHECK-NEXT: !{!"__mydata", i32 8, i32 16, !"data"} + +!llvm.raw.sections = !{!0, !1, !2, !3, !4, !5} + +; Valid: Alloc only. +!0 = !{!"__mydata", i32 8, i32 1, !"data"} +!1 = !{!"__mydata", i32 8, i32 2, !"data"} +!2 = !{!"__mydata", i32 8, i32 4, !"data"} +!3 = !{!"__mydata", i32 8, i32 7, !"data"} +!4 = !{!"__mydata", i32 8, i32 9, !"data"} +!5 = !{!"__mydata", i32 8, i32 16, !"data"} diff --git a/llvm/test/Verifier/raw-sections.ll b/llvm/test/Verifier/raw-sections.ll index 77bc01f89b06c..1778bb36ddead 100644 --- a/llvm/test/Verifier/raw-sections.ll +++ b/llvm/test/Verifier/raw-sections.ll @@ -4,6 +4,6 @@ ; CHECK: llvm.raw.sections entry operand 0 must be a string (section name) !llvm.raw.sections = !{!0, !1, !2} -!0 = !{!"__clangast", i32 8, i32 4, !"data"} +!0 = !{!"__clangast", i32 8, i32 1, !"data"} !1 = !{!"__clangast", i32 8, !"data"} -!2 = !{i32 0, i32 8, i32 4, !"data"} +!2 = !{i32 0, i32 8, i32 1, !"data"} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
