[llvm] cf3a327 - IR: Introduce !elf_section_properties for setting section properties.

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 29 16:08:17 PDT 2026


Author: Peter Collingbourne
Date: 2026-04-29T16:08:13-07:00
New Revision: cf3a327372f09815d78aa9066c19424f5a41f550

URL: https://github.com/llvm/llvm-project/commit/cf3a327372f09815d78aa9066c19424f5a41f550
DIFF: https://github.com/llvm/llvm-project/commit/cf3a327372f09815d78aa9066c19424f5a41f550.diff

LOG: IR: Introduce !elf_section_properties for setting section properties.

This new metadata type may be used to set sh_type and sh_entsize on a
global's section. The intent is that it will be used to mark up
CFI jump table sections.

Reviewers: fmayer, MaskRay, nikic, efriedma-quic

Reviewed By: fmayer

Pull Request: https://github.com/llvm/llvm-project/pull/149260

Added: 
    llvm/test/CodeGen/X86/elf-section-properties.ll
    llvm/test/Verifier/elf-section-properties.ll

Modified: 
    llvm/docs/LangRef.rst
    llvm/include/llvm/IR/FixedMetadataKinds.def
    llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
    llvm/lib/IR/Verifier.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index be4b1d8a166de..5a7e9401fb1e0 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -8905,6 +8905,25 @@ function that has had all calls to it inlined.
 
     !0 = !{ptr @bar, null, ptr @baz}
 
+'``elf_section_properties``' Metadata
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The '``elf_section_properties``' metadata is attached to a function or
+global variable and is used when writing an object file in ELF format to
+specify the values of the global's section type (`sh_type`) and entry
+size (`sh_entsize`) fields. The first operand specifies the type, and
+the second operand specifies the entry size.
+
+Example:
+
+.. code-block:: llvm
+
+    @global = global i32 1, !elf_section_properties !{i32 1879002126, i32 8}
+
+This defines a global with type ``SHT_LLVM_CFI_JUMP_TABLE`` and entry
+size 8.
+
+
 Module Flags Metadata
 =====================
 

diff  --git a/llvm/include/llvm/IR/FixedMetadataKinds.def b/llvm/include/llvm/IR/FixedMetadataKinds.def
index 6d74aff4ae250..47c221fd60fc5 100644
--- a/llvm/include/llvm/IR/FixedMetadataKinds.def
+++ b/llvm/include/llvm/IR/FixedMetadataKinds.def
@@ -61,3 +61,4 @@ LLVM_FIXED_MD_KIND(MD_implicit_ref, "implicit.ref", 46)
 LLVM_FIXED_MD_KIND(MD_nofpclass, "nofpclass", 47)
 LLVM_FIXED_MD_KIND(MD_call_target, "call_target", 48)
 LLVM_FIXED_MD_KIND(MD_inline_history, "inline_history", 49)
+LLVM_FIXED_MD_KIND(MD_elf_section_properties, "elf_section_properties", 50)

diff  --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 715b8977048fa..211d13c19e459 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -634,10 +634,11 @@ static StringRef getSectionPrefixForGlobal(SectionKind Kind, bool IsLarge) {
 static SmallString<128>
 getELFSectionNameForGlobal(const GlobalObject *GO, SectionKind Kind,
                            Mangler &Mang, const TargetMachine &TM,
-                           unsigned EntrySize, bool UniqueSectionName,
+                           bool UniqueSectionName,
                            const MachineJumpTableEntry *JTE) {
   SmallString<128> Name =
       getSectionPrefixForGlobal(Kind, TM.isLargeGlobalValue(GO));
+  unsigned EntrySize = getEntrySizeForKind(Kind);
   if (Kind.isMergeableCString()) {
     // We also need alignment here.
     // FIXME: this is getting the alignment of the character, not the
@@ -771,8 +772,8 @@ calcUniqueIDUpdateFlagsAndSize(const GlobalObject *GO, StringRef SectionName,
   // implicitly for this symbol e.g. .rodata.str1.1, then we don't need
   // to unique the section as the entry size for this symbol will be
   // compatible with implicitly created sections.
-  SmallString<128> ImplicitSectionNameStem = getELFSectionNameForGlobal(
-      GO, Kind, Mang, TM, EntrySize, false, /*MJTE=*/nullptr);
+  SmallString<128> ImplicitSectionNameStem =
+      getELFSectionNameForGlobal(GO, Kind, Mang, TM, false, /*MJTE=*/nullptr);
   if (SymbolMergeable &&
       Ctx.isELFImplicitMergeableSectionNamePrefix(SectionName) &&
       SectionName.starts_with(ImplicitSectionNameStem))
@@ -783,8 +784,9 @@ calcUniqueIDUpdateFlagsAndSize(const GlobalObject *GO, StringRef SectionName,
   return NextUniqueID++;
 }
 
-static std::tuple<StringRef, bool, unsigned>
-getGlobalObjectInfo(const GlobalObject *GO, const TargetMachine &TM) {
+static std::tuple<StringRef, bool, unsigned, unsigned, unsigned>
+getGlobalObjectInfo(const GlobalObject *GO, const TargetMachine &TM,
+                    StringRef SectionName, SectionKind Kind) {
   StringRef Group = "";
   bool IsComdat = false;
   unsigned Flags = 0;
@@ -795,7 +797,23 @@ getGlobalObjectInfo(const GlobalObject *GO, const TargetMachine &TM) {
   }
   if (TM.isLargeGlobalValue(GO))
     Flags |= ELF::SHF_X86_64_LARGE;
-  return {Group, IsComdat, Flags};
+
+  unsigned Type, EntrySize;
+  if (MDNode *MD = GO->getMetadata(LLVMContext::MD_elf_section_properties)) {
+    Type = cast<ConstantAsMetadata>(MD->getOperand(0))
+               ->getValue()
+               ->getUniqueInteger()
+               .getZExtValue();
+    EntrySize = cast<ConstantAsMetadata>(MD->getOperand(1))
+                    ->getValue()
+                    ->getUniqueInteger()
+                    .getZExtValue();
+  } else {
+    Type = getELFSectionType(SectionName, Kind);
+    EntrySize = getEntrySizeForKind(Kind);
+  }
+
+  return {Group, IsComdat, Flags, Type, EntrySize};
 }
 
 static StringRef handlePragmaClangSection(const GlobalObject *GO,
@@ -831,18 +849,18 @@ static MCSection *selectExplicitSectionGlobal(const GlobalObject *GO,
   Kind = getELFKindForNamedSection(SectionName, Kind);
 
   unsigned Flags = getELFSectionFlags(Kind, TM.getTargetTriple());
-  auto [Group, IsComdat, ExtraFlags] = getGlobalObjectInfo(GO, TM);
+  auto [Group, IsComdat, ExtraFlags, Type, EntrySize] =
+      getGlobalObjectInfo(GO, TM, SectionName, Kind);
   Flags |= ExtraFlags;
 
-  unsigned EntrySize = getEntrySizeForKind(Kind);
   const unsigned UniqueID = calcUniqueIDUpdateFlagsAndSize(
       GO, SectionName, Kind, TM, Ctx, Mang, Flags, EntrySize, NextUniqueID,
       Retain, ForceUnique);
 
   const MCSymbolELF *LinkedToSym = getLinkedToSymbol(GO, TM);
-  MCSectionELF *Section = Ctx.getELFSection(
-      SectionName, getELFSectionType(SectionName, Kind), Flags, EntrySize,
-      Group, IsComdat, UniqueID, LinkedToSym);
+  MCSectionELF *Section =
+      Ctx.getELFSection(SectionName, Type, Flags, EntrySize, Group, IsComdat,
+                        UniqueID, LinkedToSym);
   // Make sure that we did not get some other section with incompatible sh_link.
   // This should not be possible due to UniqueID code above.
   assert(Section->getLinkedToSymbol() == LinkedToSym &&
@@ -880,13 +898,6 @@ static MCSectionELF *selectELFSectionForGlobal(
     const TargetMachine &TM, bool EmitUniqueSection, unsigned Flags,
     unsigned *NextUniqueID, const MCSymbolELF *AssociatedSymbol,
     const MachineJumpTableEntry *MJTE = nullptr) {
-
-  auto [Group, IsComdat, ExtraFlags] = getGlobalObjectInfo(GO, TM);
-  Flags |= ExtraFlags;
-
-  // Get the section entry size based on the kind.
-  unsigned EntrySize = getEntrySizeForKind(Kind);
-
   bool UniqueSectionName = false;
   unsigned UniqueID = MCSection::NonUniqueID;
   if (EmitUniqueSection) {
@@ -897,15 +908,18 @@ static MCSectionELF *selectELFSectionForGlobal(
       (*NextUniqueID)++;
     }
   }
-  SmallString<128> Name = getELFSectionNameForGlobal(
-      GO, Kind, Mang, TM, EntrySize, UniqueSectionName, MJTE);
+  SmallString<128> Name =
+      getELFSectionNameForGlobal(GO, Kind, Mang, TM, UniqueSectionName, MJTE);
+
+  auto [Group, IsComdat, ExtraFlags, Type, EntrySize] =
+      getGlobalObjectInfo(GO, TM, Name, Kind);
+  Flags |= ExtraFlags;
 
   // Use 0 as the unique ID for execute-only text.
   if (Kind.isExecuteOnly())
     UniqueID = 0;
-  return Ctx.getELFSection(Name, getELFSectionType(Name, Kind), Flags,
-                           EntrySize, Group, IsComdat, UniqueID,
-                           AssociatedSymbol);
+  return Ctx.getELFSection(Name, Type, Flags, EntrySize, Group, IsComdat,
+                           UniqueID, AssociatedSymbol);
 }
 
 static MCSection *selectELFSectionForGlobal(
@@ -927,6 +941,8 @@ static MCSection *selectELFSectionForGlobal(
       Flags |= ELF::SHF_GNU_RETAIN;
     }
   }
+  if (GO->hasMetadata(LLVMContext::MD_elf_section_properties))
+    EmitUniqueSection = true;
 
   MCSectionELF *Section = selectELFSectionForGlobal(
       Ctx, GO, Kind, Mang, TM, EmitUniqueSection, Flags,

diff  --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index fe1854384e693..ec467e8b85739 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -803,6 +803,23 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) {
         }
       }
     }
+
+    if (auto *Props = GO->getMetadata(LLVMContext::MD_elf_section_properties)) {
+      Check(Props->getNumOperands() == 2,
+            "elf_section_properties metadata must have two operands", GO,
+            Props);
+      if (Props->getNumOperands() == 2) {
+        auto *Type = dyn_cast<ConstantAsMetadata>(Props->getOperand(0));
+        Check(Type, "type field must be ConstantAsMetadata", GO, Props);
+        auto *TypeInt = dyn_cast<ConstantInt>(Type->getValue());
+        Check(TypeInt, "type field must be ConstantInt", GO, Props);
+
+        auto *Entsize = dyn_cast<ConstantAsMetadata>(Props->getOperand(1));
+        Check(Entsize, "entsize field must be ConstantAsMetadata", GO, Props);
+        auto *EntsizeInt = dyn_cast<ConstantInt>(Entsize->getValue());
+        Check(EntsizeInt, "entsize field must be ConstantInt", GO, Props);
+      }
+    }
   }
 
   Check(!GV.hasAppendingLinkage() || isa<GlobalVariable>(GV),

diff  --git a/llvm/test/CodeGen/X86/elf-section-properties.ll b/llvm/test/CodeGen/X86/elf-section-properties.ll
new file mode 100644
index 0000000000000..071fdffd2ed6c
--- /dev/null
+++ b/llvm/test/CodeGen/X86/elf-section-properties.ll
@@ -0,0 +1,25 @@
+; RUN: llc < %s | FileCheck %s
+; RUN: llc -function-sections -data-sections < %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK: .section .text.implicit_section_func,"ax", at llvm_cfi_jump_table,2
+define void @implicit_section_func() !elf_section_properties !{i32 1879002126, i32 2} {
+  ret void
+}
+; CHECK: .section foo,"ax", at llvm_cfi_jump_table,4
+define void @explicit_section_func() section "foo" !elf_section_properties !{i32 1879002126, i32 4} {
+  ret void
+}
+; CHECK: .section foo,"ax", at llvm_cfi_jump_table,8,unique,1
+define void @explicit_section_func2() section "foo" !elf_section_properties !{i32 1879002126, i32 8} {
+  ret void
+}
+
+; CHECK: .section .data.implicit_section_global,"aw", at llvm_cfi_jump_table,8
+ at implicit_section_global = global i32 1, !elf_section_properties !{i32 1879002126, i32 8}
+; CHECK: .section bar,"aw", at llvm_cfi_jump_table,16
+ at explicit_section_global = global i32 1, !elf_section_properties !{i32 1879002126, i32 16}, section "bar"
+; CHECK: .section bar,"aw", at llvm_cfi_jump_table,32,unique,2
+ at explicit_section_global2 = global i32 1, !elf_section_properties !{i32 1879002126, i32 32}, section "bar"

diff  --git a/llvm/test/Verifier/elf-section-properties.ll b/llvm/test/Verifier/elf-section-properties.ll
new file mode 100644
index 0000000000000..70e50655fc2f8
--- /dev/null
+++ b/llvm/test/Verifier/elf-section-properties.ll
@@ -0,0 +1,12 @@
+; RUN: not llvm-as -disable-output < %s 2>&1 | FileCheck %s
+
+; CHECK: elf_section_properties metadata must have two operands
+ at g1 = global i32 0, !elf_section_properties !{i32 0}
+; CHECK: type field must be ConstantAsMetadata
+ at g2 = global i32 0, !elf_section_properties !{!{}, i32 0}
+; CHECK: entsize field must be ConstantAsMetadata
+ at g3 = global i32 0, !elf_section_properties !{i32 0, !{}}
+; CHECK: type field must be ConstantInt
+ at g4 = global i32 0, !elf_section_properties !{float 0.0, i32 0}
+; CHECK: entsize field must be ConstantInt
+ at g5 = global i32 0, !elf_section_properties !{i32 0, float 0.0}


        


More information about the llvm-commits mailing list