Index: llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h =================================================================== --- llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -13,11 +13,13 @@ #ifndef LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H #define LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H - + +#include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/XCOFF.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCExpr.h" #include "llvm/Target/TargetLoweringObjectFile.h" +#include namespace llvm { @@ -33,6 +35,30 @@ bool UseInitArray = false; mutable unsigned NextUniqueID = 1; // ID 0 is reserved for execute-only sections + // Mergable globals must be assigned to a section with a compatible entry size. This + // map is used to assign unique IDs to mergeable sections to distinguish between sections + // with identical names but incompatible entry sizes. This is required if mergeable globals + // are explicitly assigned to a section, e.g. via _attribute_((section(“myname”))). + 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 { + assert(Flags & ELF::SHF_MERGE); + 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; + } + }; + + mutable std::map ELFEntrySizeMap; + protected: MCSymbolRefExpr::VariantKind PLTRelativeVariantKind = MCSymbolRefExpr::VK_None; Index: llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -594,15 +594,34 @@ if (AssociatedSymbol) { UniqueID = NextUniqueID++; Flags |= ELF::SHF_LINK_ORDER; + } else { + // Mergeable globals must be placed into sections with compatible entry + // sizes. Put the global into the correct existing section or create a + // new uniqued section. + if (Flags & ELF::SHF_MERGE) { + auto i = ELFEntrySizeMap.insert(std::make_pair( + ELFEntrySizeKey{SectionName, Flags, getEntrySizeForKind(Kind)}, + NextUniqueID)); + if (i.second) + NextUniqueID++; + UniqueID = i.first->second; + } } MCSectionELF *Section = getContext().getELFSection( SectionName, getELFSectionType(SectionName, Kind), Flags, getEntrySizeForKind(Kind), Group, UniqueID, AssociatedSymbol); + // 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->getAssociatedSymbol() == AssociatedSymbol && "Associated symbol mismatch between sections"); + + // Make sure that two globals with differing sizes do not end up in the same mergeable section. + // This should not be possible due to the UniqueID code above. + assert (((Section->getEntrySize() == 0) || + (Section->getEntrySize() == getEntrySizeForKind(Kind)))); + return Section; } Index: llvm/test/CodeGen/X86/explict-section-mergeable.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/explict-section-mergeable.ll @@ -0,0 +1,28 @@ +; RUN: llc < %s -mtriple=x86_64-linux-gnu 2>&1 \ +; RUN: | FileCheck %s --check-prefixes=IMPLICIT,UNIQUE + +;; show that the implicitly generated sections are as expected +; IMPLICIT-CHECK: .section .rodata.cst4,"aM",@progbits,4 +; IMPLICIT-CHECK: .section .rodata.cst8,"aM",@progbits,8 +; IMPLICIT-CHECK: .section .rodata.str2.2,"aMS",@progbits,2 + +;; Check that the globals have been placed into several sections with +;; the same name + +; UNIQUE: .section ".clang-section-pragma","aM",@progbits,4,unique,1 +; UNIQUE-NOT: .section +; UNIQUE: explicit1: +; UNIQUE: .section ".clang-section-pragma","aM",@progbits,8,unique,2 +; UNIQUE-NOT: .section +; UNIQUE: explicit2: +; UNIQUE: .section ".clang-section-pragma","aMS",@progbits,2,unique,3 +; UNIQUE-NOT: .section +; UNIQUE: explicit3: + +@implicit1 = unnamed_addr constant [2 x i16] [i16 1, i16 1] +@implicit2 = unnamed_addr constant [2 x i32] [i32 1, i32 1] +@implicit3 = unnamed_addr constant [2 x i16] [i16 1, i16 0] + +@explicit1 = unnamed_addr constant [2 x i16] [i16 1, i16 1] "rodata-section"=".clang-section-pragma" +@explicit2 = unnamed_addr constant [2 x i32] [i32 1, i32 1] "rodata-section"=".clang-section-pragma" +@explicit3 = unnamed_addr constant [2 x i16] [i16 1, i16 0] "rodata-section"=".clang-section-pragma" Index: llvm/test/CodeGen/X86/explict-section-mergeable2.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/explict-section-mergeable2.ll @@ -0,0 +1,28 @@ +; RUN: llc < %s -mtriple=x86_64-linux-gnu 2>&1 \ +; RUN: | FileCheck %s + +;; show that the implicitly generated sections are as expected +; CHECK: .section .rodata.cst4,"aM",@progbits,4 +; CHECK: .section .rodata.cst8,"aM",@progbits,8 +; CHECK: .section .rodata.str2.2,"aMS",@progbits,2 + +;; Check that the globals have been placed into several sections with +;; the same name + +; CHECK: .section .explicit,"aM",@progbits,4,unique,1 +; CHECK-NOT: .section +; CHECK: explicit1: +; CHECK: .section .explicit,"aM",@progbits,8,unique,2 +; CHECK-NOT: .section +; CHECK: explicit2: +; CHECK: .section .explicit,"aMS",@progbits,2,unique,3 +; CHECK-NOT: .section +; CHECK: explicit3: + +@implicit1 = unnamed_addr constant [2 x i16] [i16 1, i16 1] +@implicit2 = unnamed_addr constant [2 x i32] [i32 1, i32 1] +@implicit3 = unnamed_addr constant [2 x i16] [i16 1, i16 0] + +@explicit1 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit" +@explicit2 = unnamed_addr constant [2 x i32] [i32 1, i32 1], section ".explicit" +@explicit3 = unnamed_addr constant [2 x i16] [i16 1, i16 0], section ".explicit" \ No newline at end of file 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, "some_string"); + auto *GV = + new GlobalVariable(*M, StrConstant->getType(), true, + GlobalValue::ExternalLinkage, StrConstant, "foo"); + GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + GV->setAlignment(1); GV->setSection(".debug_str"); Index: llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp =================================================================== --- llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp +++ llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp @@ -73,10 +73,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, "some_string"); + auto *GV = + new GlobalVariable(*M, StrConstant->getType(), true, + GlobalValue::ExternalLinkage, StrConstant, "foo"); + GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + GV->setAlignment(1); GV->setSection(".debug_str");