[Clang][CodeGen][ObjC]: Fix CoreFoundation on ELF with `-fconstant-cfstrings`.

[Clang][CodeGen][ObjC]: Fix non-bridged CoreFoundation builds on ELF targets
that use `-fconstant-cfstrings`. The original changes from differential 
for a similar patch to PE/COFF (https://reviews.llvm.org/D44491) did not
check for an edge case where the global could be a constant which surfaced
as an issue when building for ELF because of different linkage semantics.

This patch addresses several issues with crashes related to CF builds on ELF
as well as improves data layout by ensuring string literals that back
the actual CFConstStrings end up in .rodata in line with Mach-O.

Change itself tested with CoreFoundation on Linux x86_64 but should be valid
for BSD-like systems as well that use ELF as the native object format.

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

llvm-svn: 342883
This commit is contained in:
Kristina Brooks 2018-09-24 14:06:47 +00:00
parent edefda48d2
commit 7c142a52e2
2 changed files with 72 additions and 23 deletions

View File

@ -4109,37 +4109,48 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
llvm::Constant *Zero = llvm::Constant::getNullValue(Int32Ty);
llvm::Constant *Zeros[] = { Zero, Zero };
// If we don't already have it, get __CFConstantStringClassReference.
if (!CFConstantStringClassRef) {
llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
Ty = llvm::ArrayType::get(Ty, 0);
llvm::GlobalValue *GV = cast<llvm::GlobalValue>(
CreateRuntimeVariable(Ty, "__CFConstantStringClassReference"));
llvm::Constant *C =
CreateRuntimeVariable(Ty, "__CFConstantStringClassReference");
if (getTriple().isOSBinFormatELF() || getTriple().isOSBinFormatCOFF()) {
llvm::GlobalValue *GV = nullptr;
if ((GV = dyn_cast<llvm::GlobalValue>(C))) {
IdentifierInfo &II = getContext().Idents.get(GV->getName());
TranslationUnitDecl *TUDecl = getContext().getTranslationUnitDecl();
DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl);
if (getTriple().isOSBinFormatCOFF()) {
IdentifierInfo &II = getContext().Idents.get(GV->getName());
TranslationUnitDecl *TUDecl = getContext().getTranslationUnitDecl();
DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl);
const VarDecl *VD = nullptr;
for (const auto &Result : DC->lookup(&II))
if ((VD = dyn_cast<VarDecl>(Result)))
break;
if (!VD || !VD->hasAttr<DLLExportAttr>()) {
GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
} else {
GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
const VarDecl *VD = nullptr;
for (const auto &Result : DC->lookup(&II))
if ((VD = dyn_cast<VarDecl>(Result)))
break;
if (getTriple().isOSBinFormatELF()) {
if (!VD)
GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
}
else {
if (!VD || !VD->hasAttr<DLLExportAttr>()) {
GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
} else {
GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
}
}
setDSOLocal(GV);
}
}
setDSOLocal(GV);
// Decay array -> ptr
CFConstantStringClassRef =
llvm::ConstantExpr::getGetElementPtr(Ty, GV, Zeros);
llvm::ConstantExpr::getGetElementPtr(Ty, C, Zeros);
}
QualType CFTy = getContext().getCFConstantStringType();
@ -4185,7 +4196,11 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
if (getTriple().isOSBinFormatMachO())
GV->setSection(isUTF16 ? "__TEXT,__ustring"
: "__TEXT,__cstring,cstring_literals");
// Make sure the literal ends up in .rodata to allow for safe ICF and for
// the static linker to adjust permissions to read-only later on.
else if (getTriple().isOSBinFormatELF())
GV->setSection(".rodata");
// String.
llvm::Constant *Str =
llvm::ConstantExpr::getGetElementPtr(GV->getValueType(), GV, Zeros);

View File

@ -0,0 +1,34 @@
// RUN: %clang_cc1 -triple x86_64-elf -DCF_BUILDING_CF -DDECL -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-CF-IN-CF-DECL
// RUN: %clang_cc1 -triple x86_64-elf -DCF_BUILDING_CF -DDEFN -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-CF-IN-CF-DEFN
// RUN: %clang_cc1 -triple x86_64-elf -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-CF
// RUN: %clang_cc1 -triple x86_64-elf -DEXTERN -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-CF-EXTERN
// RUN: %clang_cc1 -Os -triple x86_64-elf -DCF_BUILDING_CF -DDECL -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-CF-IN-CF-DECL
// RUN: %clang_cc1 -Os -triple x86_64-elf -DCF_BUILDING_CF -DDEFN -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-CF-IN-CF-DEFN
// RUN: %clang_cc1 -Os -triple x86_64-elf -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-CF
// RUN: %clang_cc1 -Os -triple x86_64-elf -DEXTERN -S -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-CF-EXTERN
#if defined(CF_BUILDING_CF)
#if defined(DECL)
extern long __CFConstantStringClassReference[];
#elif defined(DEFN)
long __CFConstantStringClassReference[32];
#endif
#else
#if defined(EXTERN)
extern long __CFConstantStringClassReference[];
#else
long __CFConstantStringClassReference[];
#endif
#endif
typedef struct __CFString *CFStringRef;
const CFStringRef string = (CFStringRef)__builtin___CFStringMakeConstantString("string");
// CHECK-CF-IN-CF-DECL: @__CFConstantStringClassReference = external global [0 x i32]
// CHECK-CF-IN-CF-DEFN: @__CFConstantStringClassReference = common global [32 x i64] zeroinitializer, align 16
// CHECK-CF: @__CFConstantStringClassReference = common global [1 x i64] zeroinitializer, align 8
// CHECK-CF-EXTERN: @__CFConstantStringClassReference = external global [0 x i32]
// CHECK-CF-EXTERN: @.str = private unnamed_addr constant [7 x i8] c"string\00", section ".rodata", align 1