[clang] 86478d3 - [MC][ELF] Put explicit section name symbols into entry size compatible sections

via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 16 12:13:10 PDT 2020


Author: bd1976llvm
Date: 2020-04-16T19:12:49Z
New Revision: 86478d3de91a81978c2c310fda13f04541cd3b23

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

LOG: [MC][ELF] Put explicit section name symbols into entry size compatible sections

Ensure that symbols explicitly* assigned a section name are placed into
a section with a compatible entry size.

This is done by creating multiple sections with the same name** if
incompatible symbols are explicitly given the name of an incompatible
section, whilst:

  - Avoiding using uniqued sections where possible (for readability and
    to maximize compatibly with assemblers).

  - Creating as few SHF_MERGE sections as possible (for efficiency).

Given that each symbol is assigned to a section in a single pass, we
must decide which section each symbol is assigned to without seeing the
properties of all symbols. A stable and easy to understand assignment is
desirable. The following rules facilitate this: The "generic" section
for a given section name will be mergeable if the name is a mergeable
"default" section name (such as .debug_str), a mergeable "implicit"
section name (such as .rodata.str2.2), or MC has already created a
mergeable "generic" section for the given section name (e.g. in response
to a section directive in inline assembly). Otherwise, the "generic"
section for a given name is non-mergeable; and, non-mergeable symbols
are assigned to the "generic" section, while mergeable symbols are
assigned to uniqued sections.

Terminology:
"default" sections are those always created by MC initially, e.g. .text
or .debug_str.

"implicit" sections are those created normally by MC in response to the
symbols that it encounters, i.e. in the absence of an explicit section
name assignment on the symbol, e.g. a function foo might be placed into
a .text.foo section.

"generic" sections are those that are referred to when a unique section
ID is not supplied, e.g. if there are multiple unique .bob sections then
".quad .bob" will reference the generic .bob section. Typically, the
generic section is just the first section of a given name to be created.
Default sections are always generic.

* Typically, section names might be explicitly assigned in source code
using a language extension e.g. a section attribute: _attribute_
((section ("section-name"))) -
https://clang.llvm.org/docs/AttributeReference.html

** I refer to such sections as unique/uniqued sections. In assembly the
", unique," assembly syntax is used to express such sections.

Fixes https://bugs.llvm.org/show_bug.cgi?id=43457.

See https://reviews.llvm.org/D68101 for previous discussions leading to
this patch.

Some minor fixes were required to LLVM's tests, for tests had been using
the old behavior - which allowed for explicitly assigning globals with
incompatible entry sizes to a section.

This fix relies on the ",unique ," assembly feature. This feature is not
available until bintuils version 2.35
(https://sourceware.org/bugzilla/show_bug.cgi?id=25380). If the
integrated assembler is not being used then we avoid using this feature
for compatibility and instead try to place mergeable symbols into
non-mergeable sections or issue an error otherwise.

Differential Revision: https://reviews.llvm.org/D72194

Added: 
    llvm/test/CodeGen/X86/explicit-section-mergeable.ll

Modified: 
    clang/test/CodeGen/cfstring-elf-sections-x86_64.c
    llvm/include/llvm/IR/DiagnosticInfo.h
    llvm/include/llvm/MC/MCContext.h
    llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
    llvm/lib/MC/MCContext.cpp
    llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp
    llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/test/CodeGen/cfstring-elf-sections-x86_64.c b/clang/test/CodeGen/cfstring-elf-sections-x86_64.c
index 439113a4e855..3e300dadc5fa 100644
--- a/clang/test/CodeGen/cfstring-elf-sections-x86_64.c
+++ b/clang/test/CodeGen/cfstring-elf-sections-x86_64.c
@@ -7,12 +7,12 @@ const CFStringRef one = (CFStringRef)__builtin___CFStringMakeConstantString("one
 const CFStringRef two = (CFStringRef)__builtin___CFStringMakeConstantString("\xef\xbf\xbd\x74\xef\xbf\xbd\x77\xef\xbf\xbd\x6f");
 
 // CHECK-ELF-DATA-SECTION: .type .L.str, at object
-// CHECK-ELF-DATA-SECTION: .section .rodata,"a", at progbits
+// CHECK-ELF-DATA-SECTION: .section .rodata,"aMS", at progbits,1,unique,1
 // CHECK-ELF-DATA-SECTION: .L.str:
 // CHECK-ELF-DATA-SECTION: .asciz "one"
 
 // CHECK-ELF-DATA-SECTION: .type .L.str.1, at object
-// CHECK-ELF-DATA-SECTION: .section .rodata,"a", at progbits
+// CHECK-ELF-DATA-SECTION: .section .rodata,"aMS", at progbits,2,unique,2
 // CHECK-ELF-DATA-SECTION: .L.str.1:
 // CHECK-ELF-DATA-SECTION: .short 65533
 // CHECK-ELF-DATA-SECTION: .short 116

diff  --git a/llvm/include/llvm/IR/DiagnosticInfo.h b/llvm/include/llvm/IR/DiagnosticInfo.h
index 44db0eacca1a..a8e8a7915b2a 100644
--- a/llvm/include/llvm/IR/DiagnosticInfo.h
+++ b/llvm/include/llvm/IR/DiagnosticInfo.h
@@ -55,6 +55,7 @@ enum DiagnosticKind {
   DK_ResourceLimit,
   DK_StackSize,
   DK_Linker,
+  DK_Lowering,
   DK_DebugMetadataVersion,
   DK_DebugMetadataInvalid,
   DK_ISelFallback,

diff  --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index 9e02bd1a4be0..b1fa8e7a1d0e 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -18,6 +18,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/BinaryFormat/ELF.h"
 #include "llvm/BinaryFormat/XCOFF.h"
 #include "llvm/MC/MCAsmMacro.h"
 #include "llvm/MC/MCDwarf.h"
@@ -307,6 +308,37 @@ namespace llvm {
     /// Map of currently defined macros.
     StringMap<MCAsmMacro> MacroMap;
 
+    struct ELFEntrySizeKey {
+      std::string SectionName;
+      unsigned Flags;
+      unsigned EntrySize;
+
+      ELFEntrySizeKey(StringRef SectionName, unsigned Flags, unsigned EntrySize)
+          : SectionName(SectionName), Flags(Flags), EntrySize(EntrySize) {}
+
+      bool operator<(const ELFEntrySizeKey &Other) const {
+        if (SectionName != Other.SectionName)
+          return SectionName < Other.SectionName;
+        if ((Flags & ELF::SHF_STRINGS) != (Other.Flags & ELF::SHF_STRINGS))
+          return Other.Flags & ELF::SHF_STRINGS;
+        return EntrySize < Other.EntrySize;
+      }
+    };
+
+    // Symbols must be assigned to a section with a compatible entry
+    // size. This map is used to assign unique IDs to sections to
+    // distinguish between sections with identical names but incompatible entry
+    // sizes. This can occur when a symbol is explicitly assigned to a
+    // section, e.g. via __attribute__((section("myname"))).
+    std::map<ELFEntrySizeKey, unsigned> ELFEntrySizeMap;
+
+    // This set is used to record the generic mergeable section names seen.
+    // These are sections that are created as mergeable e.g. .debug_str. We need
+    // to avoid assigning non-mergeable symbols to these sections. It is used
+    // to prevent non-mergeable symbols being explicitly assigned  to mergeable
+    // sections (e.g. via _attribute_((section("myname")))).
+    DenseSet<StringRef> ELFSeenGenericMergeableSections;
+
   public:
     explicit MCContext(const MCAsmInfo *MAI, const MCRegisterInfo *MRI,
                        const MCObjectFileInfo *MOFI,
@@ -466,6 +498,17 @@ namespace llvm {
 
     MCSectionELF *createELFGroupSection(const MCSymbolELF *Group);
 
+    void recordELFMergeableSectionInfo(StringRef SectionName, unsigned Flags,
+                                       unsigned UniqueID, unsigned EntrySize);
+
+    bool isELFImplicitMergeableSectionNamePrefix(StringRef Name);
+
+    bool isELFGenericMergeableSection(StringRef Name);
+
+    Optional<unsigned> getELFUniqueIDForEntsize(StringRef SectionName,
+                                                unsigned Flags,
+                                                unsigned EntrySize);
+
     MCSectionCOFF *getCOFFSection(StringRef Section, unsigned Characteristics,
                                   SectionKind Kind, StringRef COMDATSymName,
                                   int Selection,

diff  --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 0acea0871dab..a5f380168c10 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -29,6 +29,8 @@
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/GlobalAlias.h"
 #include "llvm/IR/GlobalObject.h"
@@ -568,6 +570,71 @@ static unsigned getEntrySizeForKind(SectionKind Kind) {
   }
 }
 
+/// Return the section prefix name used by options FunctionsSections and
+/// DataSections.
+static StringRef getSectionPrefixForGlobal(SectionKind Kind) {
+  if (Kind.isText())
+    return ".text";
+  if (Kind.isReadOnly())
+    return ".rodata";
+  if (Kind.isBSS())
+    return ".bss";
+  if (Kind.isThreadData())
+    return ".tdata";
+  if (Kind.isThreadBSS())
+    return ".tbss";
+  if (Kind.isData())
+    return ".data";
+  if (Kind.isReadOnlyWithRel())
+    return ".data.rel.ro";
+  llvm_unreachable("Unknown section kind");
+}
+
+static SmallString<128>
+getELFSectionNameForGlobal(const GlobalObject *GO, SectionKind Kind,
+                           Mangler &Mang, const TargetMachine &TM,
+                           unsigned EntrySize, bool UniqueSectionName) {
+  SmallString<128> Name;
+  if (Kind.isMergeableCString()) {
+    // We also need alignment here.
+    // FIXME: this is getting the alignment of the character, not the
+    // alignment of the global!
+    unsigned Align = GO->getParent()->getDataLayout().getPreferredAlignment(
+        cast<GlobalVariable>(GO));
+
+    std::string SizeSpec = ".rodata.str" + utostr(EntrySize) + ".";
+    Name = SizeSpec + utostr(Align);
+  } else if (Kind.isMergeableConst()) {
+    Name = ".rodata.cst";
+    Name += utostr(EntrySize);
+  } else {
+    Name = getSectionPrefixForGlobal(Kind);
+  }
+
+  if (const auto *F = dyn_cast<Function>(GO)) {
+    if (Optional<StringRef> Prefix = F->getSectionPrefix())
+      Name += *Prefix;
+  }
+
+  if (UniqueSectionName) {
+    Name.push_back('.');
+    TM.getNameWithPrefix(Name, GO, Mang, /*MayAlwaysUsePrivate*/true);
+  }
+  return Name;
+}
+
+namespace {
+class LoweringDiagnosticInfo : public DiagnosticInfo {
+  const Twine &Msg;
+
+public:
+  LoweringDiagnosticInfo(const Twine &DiagMsg,
+                         DiagnosticSeverity Severity = DS_Error)
+      : DiagnosticInfo(DK_Lowering, Severity), Msg(DiagMsg) {}
+  void print(DiagnosticPrinter &DP) const override { DP << Msg; }
+};
+}
+
 MCSection *TargetLoweringObjectFileELF::getExplicitSectionGlobal(
     const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
   StringRef SectionName = GO->getSection();
@@ -603,6 +670,8 @@ MCSection *TargetLoweringObjectFileELF::getExplicitSectionGlobal(
     Flags |= ELF::SHF_GROUP;
   }
 
+  unsigned EntrySize = getEntrySizeForKind(Kind);
+
   // A section can have at most one associated section. Put each global with
   // MD_associated in a unique section.
   unsigned UniqueID = MCContext::GenericSectionID;
@@ -610,35 +679,75 @@ MCSection *TargetLoweringObjectFileELF::getExplicitSectionGlobal(
   if (LinkedToSym) {
     UniqueID = NextUniqueID++;
     Flags |= ELF::SHF_LINK_ORDER;
+  } else {
+    if (getContext().getAsmInfo()->useIntegratedAssembler()) {
+      // Symbols must be placed into sections with compatible entry
+      // sizes. Generate unique sections for symbols that have not
+      // been assigned to compatible sections.
+      if (Flags & ELF::SHF_MERGE) {
+        auto maybeID = getContext().getELFUniqueIDForEntsize(SectionName, Flags,
+                                                             EntrySize);
+        if (maybeID)
+          UniqueID = *maybeID;
+        else {
+          // If the user has specified the same section name as would be created
+          // 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, getMangler(), TM, EntrySize, false);
+          if (!(getContext().isELFImplicitMergeableSectionNamePrefix(
+                    SectionName) &&
+                SectionName.startswith(ImplicitSectionNameStem)))
+            UniqueID = NextUniqueID++;
+        }
+      } else {
+        // We need to unique the section if the user has explicity
+        // assigned a non-mergeable symbol to a section name for
+        // a generic mergeable section.
+        if (getContext().isELFGenericMergeableSection(SectionName)) {
+          auto maybeID = getContext().getELFUniqueIDForEntsize(
+              SectionName, Flags, EntrySize);
+          UniqueID = maybeID ? *maybeID : NextUniqueID++;
+        }
+      }
+    } else {
+      // If two symbols with 
diff ering sizes end up in the same mergeable
+      // section that section can be assigned an incorrect entry size. To avoid
+      // this we usually put symbols of the same size into distinct mergeable
+      // sections with the same name. Doing so relies on the ",unique ,"
+      // assembly feature. This feature is not avalible until bintuils
+      // version 2.35 (https://sourceware.org/bugzilla/show_bug.cgi?id=25380).
+      Flags &= ~ELF::SHF_MERGE;
+      EntrySize = 0;
+    }
   }
 
   MCSectionELF *Section = getContext().getELFSection(
       SectionName, getELFSectionType(SectionName, Kind), Flags,
-      getEntrySizeForKind(Kind), Group, UniqueID, LinkedToSym);
+      EntrySize, Group, 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 &&
          "Associated symbol mismatch between sections");
-  return Section;
-}
 
-/// Return the section prefix name used by options FunctionsSections and
-/// DataSections.
-static StringRef getSectionPrefixForGlobal(SectionKind Kind) {
-  if (Kind.isText())
-    return ".text";
-  if (Kind.isReadOnly())
-    return ".rodata";
-  if (Kind.isBSS())
-    return ".bss";
-  if (Kind.isThreadData())
-    return ".tdata";
-  if (Kind.isThreadBSS())
-    return ".tbss";
-  if (Kind.isData())
-    return ".data";
-  assert(Kind.isReadOnlyWithRel() && "Unknown section kind");
-  return ".data.rel.ro";
+  if (!getContext().getAsmInfo()->useIntegratedAssembler()) {
+    // If we are not using the integrated assembler then this symbol might have
+    // been placed in an incompatible mergeable section. Emit an error if this
+    // is the case to avoid creating broken output.
+    if ((Section->getFlags() & ELF::SHF_MERGE) &&
+        (Section->getEntrySize() != getEntrySizeForKind(Kind)))
+      GO->getContext().diagnose(LoweringDiagnosticInfo(
+          "Symbol '" + GO->getName() + "' from module '" +
+          (GO->getParent() ? GO->getParent()->getSourceFileName() : "unknown") +
+          "' required a section with entry-size=" +
+          Twine(getEntrySizeForKind(Kind)) + " but was placed in section '" +
+          SectionName + "' with entry-size=" + Twine(Section->getEntrySize()) +
+          ": Explicit assignment by pragma or attribute of an incompatible "
+          "symbol to this section?"));
+  }
+
+  return Section;
 }
 
 static MCSectionELF *selectELFSectionForGlobal(
@@ -655,39 +764,19 @@ static MCSectionELF *selectELFSectionForGlobal(
   // Get the section entry size based on the kind.
   unsigned EntrySize = getEntrySizeForKind(Kind);
 
-  SmallString<128> Name;
-  if (Kind.isMergeableCString()) {
-    // We also need alignment here.
-    // FIXME: this is getting the alignment of the character, not the
-    // alignment of the global!
-    unsigned Align = GO->getParent()->getDataLayout().getPreferredAlignment(
-        cast<GlobalVariable>(GO));
-
-    std::string SizeSpec = ".rodata.str" + utostr(EntrySize) + ".";
-    Name = SizeSpec + utostr(Align);
-  } else if (Kind.isMergeableConst()) {
-    Name = ".rodata.cst";
-    Name += utostr(EntrySize);
-  } else {
-    Name = getSectionPrefixForGlobal(Kind);
-  }
-
-  if (const auto *F = dyn_cast<Function>(GO)) {
-    const auto &OptionalPrefix = F->getSectionPrefix();
-    if (OptionalPrefix)
-      Name += *OptionalPrefix;
-  }
-
+  bool UniqueSectionName = false;
   unsigned UniqueID = MCContext::GenericSectionID;
   if (EmitUniqueSection) {
     if (TM.getUniqueSectionNames()) {
-      Name.push_back('.');
-      TM.getNameWithPrefix(Name, GO, Mang, true /*MayAlwaysUsePrivate*/);
+      UniqueSectionName = true;
     } else {
       UniqueID = *NextUniqueID;
       (*NextUniqueID)++;
     }
   }
+  SmallString<128> Name = getELFSectionNameForGlobal(
+      GO, Kind, Mang, TM, EntrySize, UniqueSectionName);
+
   // Use 0 as the unique ID for execute-only text.
   if (Kind.isExecuteOnly())
     UniqueID = 0;

diff  --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
index f68320fa9ada..1bc313553aff 100644
--- a/llvm/lib/MC/MCContext.cpp
+++ b/llvm/lib/MC/MCContext.cpp
@@ -114,6 +114,9 @@ void MCContext::reset() {
   WasmUniquingMap.clear();
   XCOFFUniquingMap.clear();
 
+  ELFEntrySizeMap.clear();
+  ELFSeenGenericMergeableSections.clear();
+
   NextID.clear();
   AllowTemporaryLabels = true;
   DwarfLocSeen = false;
@@ -441,6 +444,10 @@ MCSectionELF *MCContext::getELFSection(const Twine &Section, unsigned Type,
       createELFSectionImpl(CachedName, Type, Flags, Kind, EntrySize, GroupSym,
                            UniqueID, LinkedToSym);
   Entry.second = Result;
+
+  recordELFMergeableSectionInfo(Result->getName(), Result->getFlags(),
+                                Result->getUniqueID(), Result->getEntrySize());
+
   return Result;
 }
 
@@ -450,6 +457,40 @@ MCSectionELF *MCContext::createELFGroupSection(const MCSymbolELF *Group) {
                               MCSection::NonUniqueID, nullptr);
 }
 
+void MCContext::recordELFMergeableSectionInfo(StringRef SectionName,
+                                              unsigned Flags, unsigned UniqueID,
+                                              unsigned EntrySize) {
+  bool IsMergeable = Flags & ELF::SHF_MERGE;
+  if (IsMergeable && (UniqueID == GenericSectionID))
+    ELFSeenGenericMergeableSections.insert(SectionName);
+
+  // For mergeable sections or non-mergeable sections with a generic mergeable
+  // section name we enter their Unique ID into the ELFEntrySizeMap so that
+  // compatible globals can be assigned to the same section.
+  if (IsMergeable || isELFGenericMergeableSection(SectionName)) {
+    ELFEntrySizeMap.insert(std::make_pair(
+        ELFEntrySizeKey{SectionName, Flags, EntrySize}, UniqueID));
+  }
+}
+
+bool MCContext::isELFImplicitMergeableSectionNamePrefix(StringRef SectionName) {
+  return SectionName.startswith(".rodata.str") ||
+         SectionName.startswith(".rodata.cst");
+}
+
+bool MCContext::isELFGenericMergeableSection(StringRef SectionName) {
+  return isELFImplicitMergeableSectionNamePrefix(SectionName) ||
+         ELFSeenGenericMergeableSections.count(SectionName);
+}
+
+Optional<unsigned> MCContext::getELFUniqueIDForEntsize(StringRef SectionName,
+                                                       unsigned Flags,
+                                                       unsigned EntrySize) {
+  auto I = ELFEntrySizeMap.find(
+      MCContext::ELFEntrySizeKey{SectionName, Flags, EntrySize});
+  return (I != ELFEntrySizeMap.end()) ? Optional<unsigned>(I->second) : None;
+}
+
 MCSectionCOFF *MCContext::getCOFFSection(StringRef Section,
                                          unsigned Characteristics,
                                          SectionKind Kind,

diff  --git a/llvm/test/CodeGen/X86/explicit-section-mergeable.ll b/llvm/test/CodeGen/X86/explicit-section-mergeable.ll
new file mode 100644
index 000000000000..2b60a19247df
--- /dev/null
+++ b/llvm/test/CodeGen/X86/explicit-section-mergeable.ll
@@ -0,0 +1,296 @@
+; RUN: llc < %s -mtriple=x86_64 -unique-section-names=0 -data-sections 2>&1 \
+; RUN:     | FileCheck %s
+
+;; Several sections are created via inline assembly. We add checks
+;; for these lines as we want to use --implicit-check-not to reduce the
+;; number of checks in this file.
+; CHECK: .section .asm_mergeable1,"aMS", at progbits,2
+; CHECK-NEXT: .section .asm_nonmergeable1,"a", at progbits
+; CHECK-NEXT: .section .asm_mergeable2,"aMS", at progbits,2
+; CHECK-NEXT: .section .asm_nonmergeable2,"a", at progbits
+
+;; Test implicit section assignment for symbols
+; CHECK: .section .data,"aw", at progbits,unique,1
+; CHECK: uniquified:
+
+;; Create a uniquified symbol (as -unique-section-names=0) to test the uniqueID
+;; interaction with mergeable symbols.
+ at uniquified = global i32 1
+
+;; Test implicit section assignment for symbols to ensure that the symbols
+;; have the expected properties.
+; CHECK: .section .rodata,"a", at progbits,unique,2
+; CHECK: implicit_nonmergeable:
+; CHECK: .section .rodata.cst4,"aM", at progbits,4
+; CHECK: implicit_rodata_cst4:
+; CHECK: .section .rodata.cst8,"aM", at progbits,8
+; CHECK: implicit_rodata_cst8:
+; CHECK: .section .rodata.str4.4,"aMS", at progbits,4
+; CHECK: implicit_rodata_str4_4:
+
+ at implicit_nonmergeable  =              constant [2 x i16] [i16 1, i16 1]
+ at implicit_rodata_cst4   = unnamed_addr constant [2 x i16] [i16 1, i16 1]
+ at implicit_rodata_cst8   = unnamed_addr constant [2 x i32] [i32 1, i32 1]
+ at implicit_rodata_str4_4 = unnamed_addr constant [2 x i32] [i32 1, i32 0]
+
+;; Basic checks that mergeable globals are placed into multiple distinct
+;; sections with the same name and a compatible entry size.
+
+; CHECK: .section .explicit_basic,"aM", at progbits,4,unique,3
+; CHECK: explicit_basic_1:
+; CHECK: explicit_basic_2:
+
+;; Assign a mergeable global to a non-existing section.
+ at explicit_basic_1 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_basic"
+;; Assign a compatible mergeable global to the previous section.
+ at explicit_basic_2 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_basic"
+
+; CHECK: .section .explicit_basic,"aM", at progbits,8,unique,4
+; CHECK: explicit_basic_3:
+; CHECK: explicit_basic_4:
+
+;; Assign a symbol with an incompatible entsize (
diff erent size) to a section with the same name.
+ at explicit_basic_3 = unnamed_addr constant [2 x i32] [i32 1, i32 1], section ".explicit_basic"
+;; Assign a compatible mergeable global to the previous section.
+ at explicit_basic_4 = unnamed_addr constant [2 x i32] [i32 1, i32 1], section ".explicit_basic"
+
+; CHECK: .section .explicit_basic,"aMS", at progbits,4,unique,5
+; CHECK: explicit_basic_5:
+; CHECK: explicit_basic_6:
+
+;; Assign a symbol with an incompatible entsize (string vs non-string) to a section with the same name.
+ at explicit_basic_5 = unnamed_addr constant [2 x i32] [i32 1, i32 0], section ".explicit_basic"
+;; Assign a compatible mergeable global to the previous section.
+ at explicit_basic_6 = unnamed_addr constant [2 x i32] [i32 1, i32 0], section ".explicit_basic"
+
+; CHECK: .section .explicit_basic,"a", at progbits
+; CHECK: explicit_basic_7:
+
+;; Assign a symbol with an incompatible entsize (non-mergeable) to a mergeable section created explicitly.
+ at explicit_basic_7 = constant [2 x i16] [i16 1, i16 1], section ".explicit_basic"
+
+; CHECK: .section .explicit_initially_nonmergeable,"a", at progbits
+; CHECK: explicit_basic_8:
+; CHECK: .section .explicit_initially_nonmergeable,"aM", at progbits,4,unique,6
+; CHECK: explicit_basic_9:
+
+;; Assign a mergeble symbol to a section that initially had a non-mergeable symbol explicitly assigned to it.
+ at explicit_basic_8 = constant [2 x i16] [i16 1, i16 1], section ".explicit_initially_nonmergeable"
+ at explicit_basic_9 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_initially_nonmergeable"
+
+; CHECK: .section .explicit_initially_nonmergeable,"a", at progbits
+; CHECK: explicit_basic_10:
+; CHECK: .section .explicit_initially_nonmergeable,"aM", at progbits,4,unique,6
+; CHECK: explicit_basic_11:
+
+;; Assign compatible globals to the previously created sections.
+ at explicit_basic_10 = constant [2 x i16] [i16 1, i16 1], section ".explicit_initially_nonmergeable"
+ at explicit_basic_11 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_initially_nonmergeable"
+
+;; Check that mergeable symbols can be explicitly assigned to "default" sections.
+
+; CHECK: .section .rodata.cst16,"a", at progbits,unique,7
+; CHECK: explicit_default_1:
+
+;; Assign an incompatible (non-mergeable) symbol to a "default" mergeable section.
+ at explicit_default_1 = constant [2 x i64] [i64 1, i64 1], section ".rodata.cst16"
+
+; CHECK: .section .rodata.cst16,"aM", at progbits,16
+; CHECK: explicit_default_2:
+
+;; Assign a compatible global to a "default" mergeable section.
+ at explicit_default_2 = unnamed_addr constant [2 x i64] [i64 1, i64 1], section ".rodata.cst16"
+
+; CHECK: .section .debug_str,"MS", at progbits,1
+; CHECK: explicit_default_3:
+
+;; Non-allocatable "default" sections can have allocatable mergeable symbols with compatible entry sizes assigned to them.
+ at explicit_default_3 = unnamed_addr constant [2 x i8] [i8 1, i8 0], section ".debug_str"
+
+; CHECK: .section .debug_str,"a", at progbits,unique,8
+; CHECK: explicit_default_4:
+
+;; Non-allocatable "default" sections cannot have allocatable mergeable symbols with incompatible (non-mergeable) entry sizes assigned to them.
+ at explicit_default_4 = constant [2 x i16] [i16 1, i16 1], section ".debug_str"
+
+;; Test implicit section assignment for globals with associated globals.
+; CHECK: .section .rodata.cst4,"aMo", at progbits,4,implicit_rodata_cst4,unique,9
+; CHECK: implicit_rodata_cst4_assoc:
+; CHECK: .section .rodata.cst8,"aMo", at progbits,8,implicit_rodata_cst4,unique,10
+; CHECK: implicit_rodata_cst8_assoc:
+
+ at implicit_rodata_cst4_assoc = unnamed_addr constant [2 x i16] [i16 1, i16 1], !associated !4
+ at implicit_rodata_cst8_assoc = unnamed_addr constant [2 x i32] [i32 1, i32 1], !associated !4
+
+;; Check that globals with associated globals that are explicitly assigned
+;; to a section have been placed into distinct sections with the same name, but
+;; 
diff erent entry sizes.
+; CHECK: .section .explicit,"aMo", at progbits,4,implicit_rodata_cst4,unique,11
+; CHECK: explicit_assoc_1:
+; CHECK: .section .explicit,"aMo", at progbits,4,implicit_rodata_cst4,unique,12
+; CHECK: explicit_assoc_2:
+; CHECK: .section .explicit,"aMo", at progbits,8,implicit_rodata_cst4,unique,13
+; CHECK: explicit_assoc_3:
+
+ at explicit_assoc_1 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit", !associated !4
+ at explicit_assoc_2 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit", !associated !4
+ at explicit_assoc_3 = unnamed_addr constant [2 x i32] [i32 1, i32 1], section ".explicit", !associated !4
+
+!4 = !{[2 x i16]* @implicit_rodata_cst4}
+
+;; Test implicit section assignment for globals in distinct comdat groups.
+; CHECK: .section .rodata.cst4,"aGM", at progbits,4,f,comdat,unique,14
+; CHECK: implicit_rodata_cst4_comdat:
+; CHECK: .section .rodata.cst8,"aGM", at progbits,8,g,comdat,unique,15
+; CHECK: implicit_rodata_cst8_comdat:
+
+;; Check that globals in distinct comdat groups that are explicitly assigned
+;; to a section have been placed into distinct sections with the same name, but
+;; 
diff erent entry sizes. Due to the way that MC currently works the unique ID
+;; does not have any effect here, although it appears in the assembly. The unique ID's
+;; appear incorrect as comdats are not taken into account when looking up the unique ID
+;; for a mergeable section. However, as they have no effect it doesn't matter that they
+;; are incorrect.
+; CHECK: .section .explicit_comdat_distinct,"aM", at progbits,4,unique,16
+; CHECK: explicit_comdat_distinct_supply_uid:
+; CHECK: .section .explicit_comdat_distinct,"aGM", at progbits,4,f,comdat,unique,16
+; CHECK: explicit_comdat_distinct1:
+; CHECK: .section .explicit_comdat_distinct,"aGM", at progbits,4,g,comdat,unique,16
+; CHECK: explicit_comdat_distinct2:
+; CHECK: .section .explicit_comdat_distinct,"aGM", at progbits,8,h,comdat,unique,17
+; CHECK: explicit_comdat_distinct3:
+
+$f = comdat any
+$g = comdat any
+$h = comdat any
+
+ at implicit_rodata_cst4_comdat = unnamed_addr constant [2 x i16] [i16 1, i16 1], comdat($f)
+ at implicit_rodata_cst8_comdat = unnamed_addr constant [2 x i32] [i32 1, i32 1], comdat($g)
+
+ at explicit_comdat_distinct_supply_uid = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_comdat_distinct"
+ at explicit_comdat_distinct1 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_comdat_distinct", comdat($f)
+ at explicit_comdat_distinct2 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_comdat_distinct", comdat($g)
+ at explicit_comdat_distinct3 = unnamed_addr constant [2 x i32] [i32 1, i32 1], section ".explicit_comdat_distinct", comdat($h)
+
+;; Test implicit section assignment for globals in the same comdat group.
+; CHECK: .section .rodata.cst4,"aGM", at progbits,4,i,comdat,unique,18
+; CHECK: implicit_rodata_cst4_same_comdat:
+; CHECK: .section .rodata.cst8,"aGM", at progbits,8,i,comdat,unique,19
+; CHECK: implicit_rodata_cst8_same_comdat:
+
+;; Check that globals in the same comdat group that are explicitly assigned
+;; to a section have been placed into distinct sections with the same name, but
+;; 
diff erent entry sizes. Due to the way that MC currently works the unique ID
+;; does not have any effect here, although it appears in the assembly. The unique ID's
+;; appear incorrect as comdats are not taken into account when looking up the unique ID
+;; for a mergeable section. However, as they have no effect it doesn't matter that they
+;; are incorrect.
+; CHECK: .section .explicit_comdat_same,"aM", at progbits,4,unique,20
+; CHECK: explicit_comdat_same_supply_uid:
+; CHECK: .section .explicit_comdat_same,"aGM", at progbits,4,i,comdat,unique,20
+; CHECK: explicit_comdat_same1:
+; CHECK: explicit_comdat_same2:
+; CHECK: .section .explicit_comdat_same,"aGM", at progbits,8,i,comdat,unique,21
+; CHECK: explicit_comdat_same3:
+
+$i = comdat any
+
+ at implicit_rodata_cst4_same_comdat = unnamed_addr constant [2 x i16] [i16 1, i16 1], comdat($i)
+ at implicit_rodata_cst8_same_comdat = unnamed_addr constant [2 x i32] [i32 1, i32 1], comdat($i)
+
+ at explicit_comdat_same_supply_uid = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_comdat_same"
+ at explicit_comdat_same1 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_comdat_same", comdat($i)
+ at explicit_comdat_same2 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_comdat_same", comdat($i)
+ at explicit_comdat_same3 = unnamed_addr constant [2 x i32] [i32 1, i32 1], section ".explicit_comdat_same", comdat($i)
+
+;; Check interaction between symbols that are explicitly assigned
+;; to a section and implicitly assigned symbols.
+
+; CHECK: .section .rodata.str1.1,"aMS", at progbits,1
+; CHECK: implicit_rodata_str1_1:
+; CHECK: explicit_implicit_1:
+
+;; Assign a compatible global to an existing mergeable section created implicitly.
+ at implicit_rodata_str1_1 = unnamed_addr constant [2 x i8] [i8 1, i8 0]
+ at explicit_implicit_1 = unnamed_addr constant [2 x i8] [i8 1, i8 0], section ".rodata.str1.1"
+
+; CHECK: .section .rodata.str1.1,"a", at progbits,unique,22
+; CHECK: explicit_implicit_2:
+
+;; Assign an incompatible symbol (non-mergeable) to an existing mergeable section created implicitly.
+ at explicit_implicit_2 = constant [2 x i16] [i16 1, i16 1], section ".rodata.str1.1"
+
+; CHECK: .section .rodata.str1.1,"aMS", at progbits,1
+; CHECK: explicit_implicit_3:
+; CHECK: .section .rodata.str1.1,"a", at progbits,unique,22
+; CHECK: explicit_implicit_4:
+
+;; Assign compatible globals to the previously created sections.
+ at explicit_implicit_3 = unnamed_addr constant [2 x i8] [i8 1, i8 0], section ".rodata.str1.1"
+ at explicit_implicit_4 = constant [2 x i16] [i16 1, i16 1], section ".rodata.str1.1"
+
+; CHECK: .section .rodata.str2.2,"aMS", at progbits,2
+; CHECK: explicit_implicit_5:
+; CHECK: implicit_rodata_str2_2:
+
+;; Implicitly assign a compatible global to an existing mergeable section created explicitly.
+ at explicit_implicit_5 = unnamed_addr constant [2 x i16] [i16 1, i16 0], section ".rodata.str2.2"
+ at implicit_rodata_str2_2 = unnamed_addr constant [2 x i16] [i16 1, i16 0]
+
+;; Check the interaction with inline asm.
+
+; CHECK: .section .asm_mergeable1,"aMS", at progbits,2
+; CHECK: explicit_asm_1:
+; CHECK: .section .asm_nonmergeable1,"a", at progbits
+; CHECK: explicit_asm_2:
+; CHECK: .section .asm_mergeable1,"aM", at progbits,4,unique,23
+; CHECK: explicit_asm_3:
+; CHECK: .section .asm_nonmergeable1,"aMS", at progbits,2,unique,24
+; CHECK: explicit_asm_4:
+; CHECK: .section .asm_mergeable2,"aM", at progbits,4,unique,25
+; CHECK: explicit_asm_5:
+; CHECK: .section .asm_nonmergeable2,"aMS", at progbits,2,unique,26
+; CHECK: explicit_asm_6:
+; CHECK: .section .asm_mergeable2,"aMS", at progbits,2
+; CHECK: explicit_asm_7:
+; CHECK: .section .asm_nonmergeable2,"a", at progbits
+; CHECK: explicit_asm_8:
+
+module asm ".section .asm_mergeable1,\22aMS\22, at progbits,2"
+module asm ".section .asm_nonmergeable1,\22a\22, at progbits"
+module asm ".section .asm_mergeable2,\22aMS\22, at progbits,2"
+module asm ".section .asm_nonmergeable2,\22a\22, at progbits"
+
+;; Assign compatible symbols to sections created using inline asm.
+ at explicit_asm_1 = unnamed_addr constant [2 x i16] [i16 1, i16 0], section ".asm_mergeable1"
+ at explicit_asm_2 = constant [2 x i16] [i16 1, i16 0], section ".asm_nonmergeable1"
+;; Assign incompatible globals to the same sections.
+ at explicit_asm_3 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".asm_mergeable1"
+ at explicit_asm_4 = unnamed_addr constant [2 x i16] [i16 1, i16 0], section ".asm_nonmergeable1"
+
+;; Assign incompatible globals to sections created using inline asm.
+ at explicit_asm_5 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".asm_mergeable2"
+ at explicit_asm_6 = unnamed_addr constant [2 x i16] [i16 1, i16 0], section ".asm_nonmergeable2"
+;; Assign compatible globals to the same sections.
+ at explicit_asm_7 = unnamed_addr constant [2 x i16] [i16 1, i16 0], section ".asm_mergeable2"
+ at explicit_asm_8 = constant [2 x i16] [i16 1, i16 0], section ".asm_nonmergeable2"
+
+;; A .note.GNU-stack section is created implicitly. We add a check for this as we want to use
+;; --implicit-check-not to reduce the number of checks in this file.
+; CHECK: .section ".note.GNU-stack","", at progbits
+
+;; --no-integrated-as avoids the use of ",unique," for compatibility with older binutils.
+
+;; Error if an incompatible symbol is explicitly placed into a mergeable section.
+; RUN: not llc < %s -mtriple=x86_64 --no-integrated-as 2>&1 \
+; RUN:     | FileCheck %s --check-prefix=NO-I-AS-ERR
+; NO-I-AS-ERR: error: Symbol 'explicit_default_1' from module '<stdin>' required a section with entry-size=0 but was placed in section '.rodata.cst16' with entry-size=16: Explicit assignment by pragma or attribute of an incompatible symbol to this section?
+; NO-I-AS-ERR: error: Symbol 'explicit_default_4' from module '<stdin>' required a section with entry-size=0 but was placed in section '.debug_str' with entry-size=1: Explicit assignment by pragma or attribute of an incompatible symbol to this section?
+; NO-I-AS-ERR: error: Symbol 'explicit_implicit_2' from module '<stdin>' required a section with entry-size=0 but was placed in section '.rodata.str1.1' with entry-size=1: Explicit assignment by pragma or attribute of an incompatible symbol to this section?
+; NO-I-AS-ERR: error: Symbol 'explicit_implicit_4' from module '<stdin>' required a section with entry-size=0 but was placed in section '.rodata.str1.1' with entry-size=1: Explicit assignment by pragma or attribute of an incompatible symbol to this section?
+
+;; Don't create mergeable sections for globals with an explicit section name.
+; RUN: echo '@explicit = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit"' > %t.no_i_as.ll
+; RUN: llc < %t.no_i_as.ll -mtriple=x86_64 --no-integrated-as 2>&1 \
+; RUN:     | FileCheck %s --check-prefix=NO-I-AS
+; NO-I-AS: .section .explicit,"a", at progbits

diff  --git a/llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp
index c1eb45566cf1..02747b69b1c9 100644
--- a/llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp
@@ -77,10 +77,12 @@ TEST(LegacyRTDyldObjectLinkingLayerTest, TestSetProcessAllSections) {
   LLVMContext Context;
   auto M = std::make_unique<Module>("", Context);
   M->setTargetTriple("x86_64-unknown-linux-gnu");
-  Type *Int32Ty = IntegerType::get(Context, 32);
-  GlobalVariable *GV =
-    new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage,
-                         ConstantInt::get(Int32Ty, 42), "foo");
+  Constant *StrConstant = ConstantDataArray::getString(Context, "forty-two");
+  auto *GV =
+      new GlobalVariable(*M, StrConstant->getType(), true,
+                         GlobalValue::ExternalLinkage, StrConstant, "foo");
+  GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
+  GV->setAlignment(Align(1));
 
   GV->setSection(".debug_str");
 

diff  --git a/llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp
index 9a50571b1969..4a192c1f28ac 100644
--- a/llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp
@@ -74,10 +74,12 @@ TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) {
   LLVMContext Context;
   auto M = std::make_unique<Module>("", Context);
   M->setTargetTriple("x86_64-unknown-linux-gnu");
-  Type *Int32Ty = IntegerType::get(Context, 32);
-  GlobalVariable *GV =
-      new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage,
-                         ConstantInt::get(Int32Ty, 42), "foo");
+  Constant *StrConstant = ConstantDataArray::getString(Context, "forty-two");
+  auto *GV =
+      new GlobalVariable(*M, StrConstant->getType(), true,
+                         GlobalValue::ExternalLinkage, StrConstant, "foo");
+  GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
+  GV->setAlignment(Align(1));
 
   GV->setSection(".debug_str");
 


        


More information about the cfe-commits mailing list