Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -187,6 +187,10 @@ def ext_flexible_array_init : Extension< "flexible array initialization is a GNU extension">, InGroup; +// GV Initilizer for ROPI/RWPI +def err_gv_initilized_with_address: Error< + "'%0' cannot be initilized using address of '%1' with '%2' relocation">; + // Declarations. def ext_duplicate_declspec : ExtWarn<"duplicate '%0' declaration specifier">, InGroup; Index: lib/CodeGen/CGDecl.cpp =================================================================== --- lib/CodeGen/CGDecl.cpp +++ lib/CodeGen/CGDecl.cpp @@ -350,6 +350,8 @@ } GV->setConstant(CGM.isTypeConstant(D.getType(), true)); + if (!CGM.isValidInitForPI(Init, GV->getName(), D.getLocation())) + return nullptr; GV->setInitializer(Init); if (hasNontrivialDestruction(D.getType())) { @@ -395,6 +397,8 @@ // If this value has an initializer, emit it. if (D.getInit() && !isCudaSharedVar) var = AddInitializerToStaticVarDecl(D, var); + if (!var) + return; var->setAlignment(alignment.getQuantity()); Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -500,6 +500,9 @@ /// MDNodes. llvm::DenseMap MetadataIdMap; + /// The relocaton model for ARM. + bool IsROPI, IsRWPI; + public: CodeGenModule(ASTContext &C, const HeaderSearchOptions &headersearchopts, const PreprocessorOptions &ppopts, @@ -1189,6 +1192,10 @@ /// \param QT is the clang QualType of the null pointer. llvm::Constant *getNullPointer(llvm::PointerType *T, QualType QT); + /// Check if a static initialization is valid for ROPI/RWPI. + bool isValidInitForPI(const llvm::Constant *Init, StringRef GVName, + SourceLocation Loc); + private: llvm::Constant * GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D, Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -159,6 +159,9 @@ // CoverageMappingModuleGen object. if (CodeGenOpts.CoverageMapping) CoverageMapping.reset(new CoverageMappingModuleGen(*this, *CoverageInfo)); + + IsROPI = StringRef(CodeGenOpts.RelocationModel).startswith("ropi"); + IsRWPI = StringRef(CodeGenOpts.RelocationModel).endswith("rwpi"); } CodeGenModule::~CodeGenModule() {} @@ -2505,6 +2508,49 @@ GO.setComdat(TheModule.getOrInsertComdat(GO.getName())); } +/// Check if the address of a GV is used in the Init expr and the consntness +/// matches with IsROPI. If such a GV is used, returns it. +static const llvm::Constant *UseAddrOfGlobalVar(const llvm::Constant *Init, + bool IsROPI) { + if (!Init) + return nullptr; + if (isa(Init)) { + bool IsConstGV = isa(Init); + if (!IsConstGV) { + if (isa(Init)) + IsConstGV = dyn_cast(Init)->isConstant(); + else + IsConstGV = UseAddrOfGlobalVar( + dyn_cast(Init)->getAliasee(), IsROPI); + } + return IsConstGV == IsROPI ? Init : nullptr; + } + if (isa(Init)) { + for (auto &Op : Init->operands()) { + const llvm::Constant *C = dyn_cast(Op); + if (auto UsedGV = UseAddrOfGlobalVar(C, IsROPI)) + return UsedGV; + } + return nullptr; + } + return nullptr; +} + +bool CodeGenModule::isValidInitForPI(const llvm::Constant *Init, + StringRef GVName, SourceLocation Loc) { + // when RelocationModel is "ropi", "rwpi" or "ropi-rwpi", we cannot + // statically initialize a GV with the absolute address of another GV that has + // ropi/rwpi relocation type. + auto UsedGV = IsROPI ? UseAddrOfGlobalVar(Init, true) : nullptr; + UsedGV = IsRWPI ? UseAddrOfGlobalVar(Init, false) : UsedGV; + if (UsedGV) { + Diags.Report(Loc, diag::err_gv_initilized_with_address) + << GVName << UsedGV->getName() << CodeGenOpts.RelocationModel; + return false; + } + return true; +} + /// Pass IsTentative as true if you want to create a tentative definition. void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, bool IsTentative) { @@ -2543,7 +2589,6 @@ } else { initializedGlobalDecl = GlobalDecl(D); Init = EmitConstantInit(*InitDecl); - if (!Init) { QualType T = InitExpr->getType(); if (D->getType()->isReferenceType()) @@ -2656,6 +2701,10 @@ Linkage = llvm::GlobalValue::InternalLinkage; } } + + if (!isValidInitForPI(Init, GV->getName(), D->getLocation())) + return; + GV->setInitializer(Init); // If it is safe to mark the global 'constant', do so now. Index: test/CodeGen/arm-ropi-rwpi.c =================================================================== --- /dev/null +++ test/CodeGen/arm-ropi-rwpi.c @@ -0,0 +1,56 @@ +// REQUIRES: arm-registered-target + +// OK with local initialization, rwpi with const gv and ropi with non-const gv. +// RUN: %clang_cc1 -triple armv7 -mrelocation-model ropi-rwpi %s -S -o /dev/null +// RUN: %clang_cc1 -triple armv7 -mrelocation-model rwpi -DTEST_RO_1 -DTEST_RO_2 -DTEST_RO_STATIC %s -S -o /dev/null +// RUN: %clang_cc1 -triple armv7 -mrelocation-model ropi -DTEST_RW_1 -DTEST_RW_STATIC %s -S -o /dev/null + +// RUN: not %clang_cc1 -triple armv7 -mrelocation-model ropi -DTEST_RO_1 %s -S -o /dev/null 2>&1 | FileCheck %s -check-prefix=CHECK-RO-1 +// RUN: not %clang_cc1 -triple armv7 -mrelocation-model ropi -DTEST_RO_2 %s -S -o /dev/null 2>&1 | FileCheck %s -check-prefix=CHECK-RO-2 +// RUN: not %clang_cc1 -triple armv7 -mrelocation-model ropi -DTEST_RO_STATIC %s -S -o /dev/null 2>&1 | FileCheck %s -check-prefix=CHECK-RO-STATIC + +// RUN: not %clang_cc1 -triple armv7 -mrelocation-model rwpi -DTEST_RW_1 %s -S -o /dev/null 2>&1 | FileCheck %s -check-prefix=CHECK-RW-1 + +// RUN: not %clang_cc1 -triple armv7 -mrelocation-model ropi-rwpi -DTEST_RW_STATIC %s -S -o /dev/null 2>&1 | FileCheck %s -check-prefix=CHECK-RW-STATIC + +extern int func(void); + +extern int gv; + +extern const int c_gv; + +#ifdef TEST_RO_1 +void *p1 = &func; +#endif +// CHECK-RO-1: error: 'p1' cannot be initilized using address of 'func' with 'ropi' relocation + +#ifdef TEST_RO_2 +const void *p2 = &c_gv; +#endif +// CHECK-RO-2: error: 'p2' cannot be initilized using address of 'c_gv' with 'ropi' relocation + +#ifdef TEST_RO_STATIC +void bar() { + static void *sp = &func; +} +#endif +// CHECK-RO-STATIC: error: 'bar.sp' cannot be initilized using address of 'func' with 'ropi' relocation + +#ifdef TEST_RW_1 +void *p3 = &gv; +#endif +// CHECK-RW-1: error: 'p3' cannot be initilized using address of 'gv' with 'rwpi' relocation + +#ifdef TEST_RW_STATIC +void bar2() { + static void *sp = &gv; +} +#endif +// CHECK-RW-STATIC: error: 'bar2.sp' cannot be initilized using address of 'gv' with 'ropi-rwpi' relocation + +unsigned test() { + unsigned a = (unsigned)&func; + unsigned b = (unsigned)&gv; + unsigned c = (unsigned)&c_gv; + return a + b + c; +}