Index: clang/include/clang/Basic/DiagnosticFrontendKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -21,6 +21,8 @@ def note_fe_inline_asm_here : Note<"instantiated into assembly here">; def err_fe_cannot_link_module : Error<"cannot link module '%0': %1">, DefaultFatal; +def err_fe_cannot_lower_module : Error<"cannot lower module: %0">, + DefaultFatal; def warn_fe_frame_larger_than : Warning<"stack frame size of %0 bytes in %q1">, BackendInfo, InGroup; Index: clang/lib/CodeGen/CodeGenAction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenAction.cpp +++ clang/lib/CodeGen/CodeGenAction.cpp @@ -822,6 +822,9 @@ return; DiagID = diag::err_fe_cannot_link_module; break; + case DK_Lowering: + DiagID = diag::err_fe_cannot_lower_module; + break; case llvm::DK_OptimizationRemark: // Optimization remarks are always handled completely by this // handler. There is no generic way of emitting them. @@ -891,6 +894,11 @@ return; } + if (DiagID == diag::err_fe_cannot_lower_module) { + Diags.Report(diag::err_fe_cannot_lower_module) << MsgStorage; + return; + } + // Report the backend message using the usual diagnostic mechanism. FullSourceLoc Loc; Diags.Report(Loc, DiagID).AddString(MsgStorage); 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 Index: clang/test/CodeGen/lowering_error.c =================================================================== --- /dev/null +++ clang/test/CodeGen/lowering_error.c @@ -0,0 +1,8 @@ +// RUN: not %clang_cc1 -triple x86_64 -S -no-integrated-as -o - %s 2>&1 \ +// RUN: | FileCheck %s + +__attribute__ ((section (".debug_str"))) +// CHECK: fatal error: cannot lower module: Symbol 'f' from module '{{.*}}lowering_error.c' 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? +int f (void) { + return 42; +} 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: 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 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 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 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 getELFUniqueIDForEntsize(StringRef SectionName, + unsigned Flags, + unsigned EntrySize); + MCSectionCOFF *getCOFFSection(StringRef Section, unsigned Characteristics, SectionKind Kind, StringRef COMDATSymName, int Selection, 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" @@ -567,6 +569,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(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(GO)) { + if (Optional 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(); @@ -602,6 +669,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; @@ -609,37 +678,77 @@ 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"); + + 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; } -/// 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"; -} - static MCSectionELF *selectELFSectionForGlobal( MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang, const TargetMachine &TM, bool EmitUniqueSection, unsigned Flags, @@ -654,39 +763,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(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(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/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; @@ -429,6 +432,10 @@ createELFSectionImpl(CachedName, Type, Flags, Kind, EntrySize, GroupSym, UniqueID, LinkedToSym); Entry.second = Result; + + recordELFMergeableSectionInfo(Result->getSectionName(), Result->getFlags(), + Result->getUniqueID(), Result->getEntrySize()); + return Result; } @@ -438,6 +445,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 MCContext::getELFUniqueIDForEntsize(StringRef SectionName, + unsigned Flags, + unsigned EntrySize) { + auto I = ELFEntrySizeMap.find( + MCContext::ELFEntrySizeKey{SectionName, Flags, EntrySize}); + return (I != ELFEntrySizeMap.end()) ? Optional(I->second) : None; +} + MCSectionCOFF *MCContext::getCOFFSection(StringRef Section, unsigned Characteristics, SectionKind Kind, Index: llvm/test/CodeGen/X86/explict-section-mergeable.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/explict-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 '' 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 '' 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 '' 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 '' 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/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("", 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/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("", 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");