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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits