This revision was automatically updated to reflect the committed changes.
Closed by commit rG86478d3de91a: [MC][ELF] Put explicit section name symbols 
into entry size compatible sections (authored by bd1976llvm).
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D72194/new/

https://reviews.llvm.org/D72194

Files:
  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/test/CodeGen/X86/explicit-section-mergeable.ll
  llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp
  llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp

Index: llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp
===================================================================
--- llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp
+++ llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp
@@ -74,10 +74,12 @@
   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");
 
Index: llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp
===================================================================
--- llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp
+++ llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp
@@ -77,10 +77,12 @@
   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");
 
Index: llvm/test/CodeGen/X86/explicit-section-mergeable.ll
===================================================================
--- /dev/null
+++ 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",@progbits,2
+; CHECK-NEXT: .section .asm_nonmergeable1,"a",@progbits
+; CHECK-NEXT: .section .asm_mergeable2,"aMS",@progbits,2
+; CHECK-NEXT: .section .asm_nonmergeable2,"a",@progbits
+
+;; Test implicit section assignment for symbols
+; CHECK: .section .data,"aw",@progbits,unique,1
+; CHECK: uniquified:
+
+;; Create a uniquified symbol (as -unique-section-names=0) to test the uniqueID
+;; interaction with mergeable symbols.
+@uniquified = global i32 1
+
+;; Test implicit section assignment for symbols to ensure that the symbols
+;; have the expected properties.
+; CHECK: .section .rodata,"a",@progbits,unique,2
+; CHECK: implicit_nonmergeable:
+; CHECK: .section .rodata.cst4,"aM",@progbits,4
+; CHECK: implicit_rodata_cst4:
+; CHECK: .section .rodata.cst8,"aM",@progbits,8
+; CHECK: implicit_rodata_cst8:
+; CHECK: .section .rodata.str4.4,"aMS",@progbits,4
+; CHECK: implicit_rodata_str4_4:
+
+@implicit_nonmergeable  =              constant [2 x i16] [i16 1, i16 1]
+@implicit_rodata_cst4   = unnamed_addr constant [2 x i16] [i16 1, i16 1]
+@implicit_rodata_cst8   = unnamed_addr constant [2 x i32] [i32 1, i32 1]
+@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",@progbits,4,unique,3
+; CHECK: explicit_basic_1:
+; CHECK: explicit_basic_2:
+
+;; Assign a mergeable global to a non-existing section.
+@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.
+@explicit_basic_2 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_basic"
+
+; CHECK: .section .explicit_basic,"aM",@progbits,8,unique,4
+; CHECK: explicit_basic_3:
+; CHECK: explicit_basic_4:
+
+;; Assign a symbol with an incompatible entsize (different size) to a section with the same name.
+@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.
+@explicit_basic_4 = unnamed_addr constant [2 x i32] [i32 1, i32 1], section ".explicit_basic"
+
+; CHECK: .section .explicit_basic,"aMS",@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.
+@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.
+@explicit_basic_6 = unnamed_addr constant [2 x i32] [i32 1, i32 0], section ".explicit_basic"
+
+; CHECK: .section .explicit_basic,"a",@progbits
+; CHECK: explicit_basic_7:
+
+;; Assign a symbol with an incompatible entsize (non-mergeable) to a mergeable section created explicitly.
+@explicit_basic_7 = constant [2 x i16] [i16 1, i16 1], section ".explicit_basic"
+
+; CHECK: .section .explicit_initially_nonmergeable,"a",@progbits
+; CHECK: explicit_basic_8:
+; CHECK: .section .explicit_initially_nonmergeable,"aM",@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.
+@explicit_basic_8 = constant [2 x i16] [i16 1, i16 1], section ".explicit_initially_nonmergeable"
+@explicit_basic_9 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_initially_nonmergeable"
+
+; CHECK: .section .explicit_initially_nonmergeable,"a",@progbits
+; CHECK: explicit_basic_10:
+; CHECK: .section .explicit_initially_nonmergeable,"aM",@progbits,4,unique,6
+; CHECK: explicit_basic_11:
+
+;; Assign compatible globals to the previously created sections.
+@explicit_basic_10 = constant [2 x i16] [i16 1, i16 1], section ".explicit_initially_nonmergeable"
+@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",@progbits,unique,7
+; CHECK: explicit_default_1:
+
+;; Assign an incompatible (non-mergeable) symbol to a "default" mergeable section.
+@explicit_default_1 = constant [2 x i64] [i64 1, i64 1], section ".rodata.cst16"
+
+; CHECK: .section .rodata.cst16,"aM",@progbits,16
+; CHECK: explicit_default_2:
+
+;; Assign a compatible global to a "default" mergeable section.
+@explicit_default_2 = unnamed_addr constant [2 x i64] [i64 1, i64 1], section ".rodata.cst16"
+
+; CHECK: .section .debug_str,"MS",@progbits,1
+; CHECK: explicit_default_3:
+
+;; Non-allocatable "default" sections can have allocatable mergeable symbols with compatible entry sizes assigned to them.
+@explicit_default_3 = unnamed_addr constant [2 x i8] [i8 1, i8 0], section ".debug_str"
+
+; CHECK: .section .debug_str,"a",@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.
+@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",@progbits,4,implicit_rodata_cst4,unique,9
+; CHECK: implicit_rodata_cst4_assoc:
+; CHECK: .section .rodata.cst8,"aMo",@progbits,8,implicit_rodata_cst4,unique,10
+; CHECK: implicit_rodata_cst8_assoc:
+
+@implicit_rodata_cst4_assoc = unnamed_addr constant [2 x i16] [i16 1, i16 1], !associated !4
+@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
+;; different entry sizes.
+; CHECK: .section .explicit,"aMo",@progbits,4,implicit_rodata_cst4,unique,11
+; CHECK: explicit_assoc_1:
+; CHECK: .section .explicit,"aMo",@progbits,4,implicit_rodata_cst4,unique,12
+; CHECK: explicit_assoc_2:
+; CHECK: .section .explicit,"aMo",@progbits,8,implicit_rodata_cst4,unique,13
+; CHECK: explicit_assoc_3:
+
+@explicit_assoc_1 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit", !associated !4
+@explicit_assoc_2 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit", !associated !4
+@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",@progbits,4,f,comdat,unique,14
+; CHECK: implicit_rodata_cst4_comdat:
+; CHECK: .section .rodata.cst8,"aGM",@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
+;; different 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",@progbits,4,unique,16
+; CHECK: explicit_comdat_distinct_supply_uid:
+; CHECK: .section .explicit_comdat_distinct,"aGM",@progbits,4,f,comdat,unique,16
+; CHECK: explicit_comdat_distinct1:
+; CHECK: .section .explicit_comdat_distinct,"aGM",@progbits,4,g,comdat,unique,16
+; CHECK: explicit_comdat_distinct2:
+; CHECK: .section .explicit_comdat_distinct,"aGM",@progbits,8,h,comdat,unique,17
+; CHECK: explicit_comdat_distinct3:
+
+$f = comdat any
+$g = comdat any
+$h = comdat any
+
+@implicit_rodata_cst4_comdat = unnamed_addr constant [2 x i16] [i16 1, i16 1], comdat($f)
+@implicit_rodata_cst8_comdat = unnamed_addr constant [2 x i32] [i32 1, i32 1], comdat($g)
+
+@explicit_comdat_distinct_supply_uid = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_comdat_distinct"
+@explicit_comdat_distinct1 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_comdat_distinct", comdat($f)
+@explicit_comdat_distinct2 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_comdat_distinct", comdat($g)
+@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",@progbits,4,i,comdat,unique,18
+; CHECK: implicit_rodata_cst4_same_comdat:
+; CHECK: .section .rodata.cst8,"aGM",@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
+;; different 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",@progbits,4,unique,20
+; CHECK: explicit_comdat_same_supply_uid:
+; CHECK: .section .explicit_comdat_same,"aGM",@progbits,4,i,comdat,unique,20
+; CHECK: explicit_comdat_same1:
+; CHECK: explicit_comdat_same2:
+; CHECK: .section .explicit_comdat_same,"aGM",@progbits,8,i,comdat,unique,21
+; CHECK: explicit_comdat_same3:
+
+$i = comdat any
+
+@implicit_rodata_cst4_same_comdat = unnamed_addr constant [2 x i16] [i16 1, i16 1], comdat($i)
+@implicit_rodata_cst8_same_comdat = unnamed_addr constant [2 x i32] [i32 1, i32 1], comdat($i)
+
+@explicit_comdat_same_supply_uid = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_comdat_same"
+@explicit_comdat_same1 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_comdat_same", comdat($i)
+@explicit_comdat_same2 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit_comdat_same", comdat($i)
+@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",@progbits,1
+; CHECK: implicit_rodata_str1_1:
+; CHECK: explicit_implicit_1:
+
+;; Assign a compatible global to an existing mergeable section created implicitly.
+@implicit_rodata_str1_1 = unnamed_addr constant [2 x i8] [i8 1, i8 0]
+@explicit_implicit_1 = unnamed_addr constant [2 x i8] [i8 1, i8 0], section ".rodata.str1.1"
+
+; CHECK: .section .rodata.str1.1,"a",@progbits,unique,22
+; CHECK: explicit_implicit_2:
+
+;; Assign an incompatible symbol (non-mergeable) to an existing mergeable section created implicitly.
+@explicit_implicit_2 = constant [2 x i16] [i16 1, i16 1], section ".rodata.str1.1"
+
+; CHECK: .section .rodata.str1.1,"aMS",@progbits,1
+; CHECK: explicit_implicit_3:
+; CHECK: .section .rodata.str1.1,"a",@progbits,unique,22
+; CHECK: explicit_implicit_4:
+
+;; Assign compatible globals to the previously created sections.
+@explicit_implicit_3 = unnamed_addr constant [2 x i8] [i8 1, i8 0], section ".rodata.str1.1"
+@explicit_implicit_4 = constant [2 x i16] [i16 1, i16 1], section ".rodata.str1.1"
+
+; CHECK: .section .rodata.str2.2,"aMS",@progbits,2
+; CHECK: explicit_implicit_5:
+; CHECK: implicit_rodata_str2_2:
+
+;; Implicitly assign a compatible global to an existing mergeable section created explicitly.
+@explicit_implicit_5 = unnamed_addr constant [2 x i16] [i16 1, i16 0], section ".rodata.str2.2"
+@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",@progbits,2
+; CHECK: explicit_asm_1:
+; CHECK: .section .asm_nonmergeable1,"a",@progbits
+; CHECK: explicit_asm_2:
+; CHECK: .section .asm_mergeable1,"aM",@progbits,4,unique,23
+; CHECK: explicit_asm_3:
+; CHECK: .section .asm_nonmergeable1,"aMS",@progbits,2,unique,24
+; CHECK: explicit_asm_4:
+; CHECK: .section .asm_mergeable2,"aM",@progbits,4,unique,25
+; CHECK: explicit_asm_5:
+; CHECK: .section .asm_nonmergeable2,"aMS",@progbits,2,unique,26
+; CHECK: explicit_asm_6:
+; CHECK: .section .asm_mergeable2,"aMS",@progbits,2
+; CHECK: explicit_asm_7:
+; CHECK: .section .asm_nonmergeable2,"a",@progbits
+; CHECK: explicit_asm_8:
+
+module asm ".section .asm_mergeable1,\22aMS\22,@progbits,2"
+module asm ".section .asm_nonmergeable1,\22a\22,@progbits"
+module asm ".section .asm_mergeable2,\22aMS\22,@progbits,2"
+module asm ".section .asm_nonmergeable2,\22a\22,@progbits"
+
+;; Assign compatible symbols to sections created using inline asm.
+@explicit_asm_1 = unnamed_addr constant [2 x i16] [i16 1, i16 0], section ".asm_mergeable1"
+@explicit_asm_2 = constant [2 x i16] [i16 1, i16 0], section ".asm_nonmergeable1"
+;; Assign incompatible globals to the same sections.
+@explicit_asm_3 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".asm_mergeable1"
+@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.
+@explicit_asm_5 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".asm_mergeable2"
+@explicit_asm_6 = unnamed_addr constant [2 x i16] [i16 1, i16 0], section ".asm_nonmergeable2"
+;; Assign compatible globals to the same sections.
+@explicit_asm_7 = unnamed_addr constant [2 x i16] [i16 1, i16 0], section ".asm_mergeable2"
+@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","",@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",@progbits
Index: llvm/lib/MC/MCContext.cpp
===================================================================
--- llvm/lib/MC/MCContext.cpp
+++ llvm/lib/MC/MCContext.cpp
@@ -114,6 +114,9 @@
   WasmUniquingMap.clear();
   XCOFFUniquingMap.clear();
 
+  ELFEntrySizeMap.clear();
+  ELFSeenGenericMergeableSections.clear();
+
   NextID.clear();
   AllowTemporaryLabels = true;
   DwarfLocSeen = false;
@@ -441,6 +444,10 @@
       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 @@
                               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,
Index: llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
===================================================================
--- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ 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 @@
   }
 }
 
+/// 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 @@
     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 @@
   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 differing 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 @@
   // 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;
Index: llvm/include/llvm/MC/MCContext.h
===================================================================
--- llvm/include/llvm/MC/MCContext.h
+++ 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 @@
     /// 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 @@
 
     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,
Index: llvm/include/llvm/IR/DiagnosticInfo.h
===================================================================
--- llvm/include/llvm/IR/DiagnosticInfo.h
+++ llvm/include/llvm/IR/DiagnosticInfo.h
@@ -55,6 +55,7 @@
   DK_ResourceLimit,
   DK_StackSize,
   DK_Linker,
+  DK_Lowering,
   DK_DebugMetadataVersion,
   DK_DebugMetadataInvalid,
   DK_ISelFallback,
Index: clang/test/CodeGen/cfstring-elf-sections-x86_64.c
===================================================================
--- clang/test/CodeGen/cfstring-elf-sections-x86_64.c
+++ clang/test/CodeGen/cfstring-elf-sections-x86_64.c
@@ -7,12 +7,12 @@
 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,@object
-// CHECK-ELF-DATA-SECTION: .section .rodata,"a",@progbits
+// CHECK-ELF-DATA-SECTION: .section .rodata,"aMS",@progbits,1,unique,1
 // CHECK-ELF-DATA-SECTION: .L.str:
 // CHECK-ELF-DATA-SECTION: .asciz "one"
 
 // CHECK-ELF-DATA-SECTION: .type .L.str.1,@object
-// CHECK-ELF-DATA-SECTION: .section .rodata,"a",@progbits
+// CHECK-ELF-DATA-SECTION: .section .rodata,"aMS",@progbits,2,unique,2
 // CHECK-ELF-DATA-SECTION: .L.str.1:
 // CHECK-ELF-DATA-SECTION: .short 65533
 // CHECK-ELF-DATA-SECTION: .short 116
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to