diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 730ffabe829d6..baf67301f6ad8 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -8588,6 +8588,24 @@ Example: The ``nofree`` metadata indicates the memory pointed by the pointer will not be freed after the attached instruction. +'``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 0603abcd6a4da..1c62087dd1b06 100644 --- a/llvm/include/llvm/IR/FixedMetadataKinds.def +++ b/llvm/include/llvm/IR/FixedMetadataKinds.def @@ -56,3 +56,4 @@ LLVM_FIXED_MD_KIND(MD_noalias_addrspace, "noalias.addrspace", 41) LLVM_FIXED_MD_KIND(MD_callee_type, "callee_type", 42) LLVM_FIXED_MD_KIND(MD_nofree, "nofree", 43) LLVM_FIXED_MD_KIND(MD_captures, "captures", 44) +LLVM_FIXED_MD_KIND(MD_elf_section_properties, "elf_section_properties", 45) diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index ae681b9aebdfb..5c8823fc19b95 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 -getGlobalObjectInfo(const GlobalObject *GO, const TargetMachine &TM) { +static std::tuple +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(MD->getOperand(0)) + ->getValue() + ->getUniqueInteger() + .getZExtValue(); + EntrySize = cast(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 6b3cd27b77a7a..9bea609ef7770 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -769,6 +769,22 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) { DL.getIntPtrType(GO->getType()), RangeLikeMetadataKind::AbsoluteSymbol); } + + 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(Props->getOperand(0)); + Check(Type, "type field must be ConstantAsMetadata", GO, Props); + auto *TypeInt = dyn_cast(Type->getValue()); + Check(TypeInt, "type field must be ConstantInt", GO, Props); + + auto *Entsize = dyn_cast(Props->getOperand(1)); + Check(Entsize, "entsize field must be ConstantAsMetadata", GO, Props); + auto *EntsizeInt = dyn_cast(Entsize->getValue()); + Check(EntsizeInt, "entsize field must be ConstantInt", GO, Props); + } + } } Check(!GV.hasAppendingLinkage() || isa(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..fe5a5940dfd5b --- /dev/null +++ b/llvm/test/CodeGen/X86/elf-section-properties.ll @@ -0,0 +1,19 @@ +; 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",@llvm_cfi_jump_table,2 +define void @implicit_section_func() !elf_section_properties !{i32 1879002126, i32 2} { + ret void +} +; CHECK: .section foo,"ax",@llvm_cfi_jump_table,4 +define void @explicit_section_func() section "foo" !elf_section_properties !{i32 1879002126, i32 4} { + ret void +} + +; CHECK: .section .data.implicit_section_global,"aw",@llvm_cfi_jump_table,8 +@implicit_section_global = global i32 1, !elf_section_properties !{i32 1879002126, i32 8} +; CHECK: .section bar,"aw",@llvm_cfi_jump_table,16 +@explicit_section_global = global i32 1, !elf_section_properties !{i32 1879002126, i32 16}, 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..3ec4a8f5d7d66 --- /dev/null +++ b/llvm/test/Verifier/elf-section-properties.ll @@ -0,0 +1,12 @@ +; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s + +; CHECK: elf_section_properties metadata must have two operands +@g1 = global i32 0, !elf_section_properties !{i32 0} +; CHECK: type field must be ConstantAsMetadata +@g2 = global i32 0, !elf_section_properties !{!{}, i32 0} +; CHECK: entsize field must be ConstantAsMetadata +@g3 = global i32 0, !elf_section_properties !{i32 0, !{}} +; CHECK: type field must be ConstantInt +@g4 = global i32 0, !elf_section_properties !{float 0.0, i32 0} +; CHECK: entsize field must be ConstantInt +@g5 = global i32 0, !elf_section_properties !{i32 0, float 0.0}