weimingz created this revision.
weimingz added reviewers: olista01, jmolloy.
weimingz added a subscriber: cfe-commits.
Herald added subscribers: rengolin, aemerson.

This patch adds diagnoses when initializing a global variable using the address 
of another global variable that uses ROPI/RWPI relocation model.

For example, 
int a;
extern void foo();
int *x = &a;            // we cannot statically initialize x with -frwpi 
void *y = &foo();  // we can't statically initialize y with -fropi

The above code will trigger diagnoses like:

  error: 'x' cannot be initialized using address of 'a' with 'rwpi' relocation


https://reviews.llvm.org/D28526

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CodeGenModule.cpp
  lib/CodeGen/CodeGenModule.h
  test/CodeGen/arm-ropi-rwpi.c

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;
+}
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -500,6 +500,9 @@
   /// MDNodes.
   llvm::DenseMap<QualType, llvm::Metadata *> 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<llvm::GlobalValue>(Init)) {
+    bool IsConstGV = isa<llvm::Function>(Init);
+    if (!IsConstGV) {
+      if (isa<llvm::GlobalVariable>(Init))
+        IsConstGV = dyn_cast<llvm::GlobalVariable>(Init)->isConstant();
+      else
+        IsConstGV = UseAddrOfGlobalVar(
+            dyn_cast<llvm::GlobalAlias>(Init)->getAliasee(), IsROPI);
+    }
+    return IsConstGV == IsROPI ? Init : nullptr;
+  }
+  if (isa<llvm::ConstantExpr>(Init)) {
+    for (auto &Op : Init->operands()) {
+      const llvm::Constant *C = dyn_cast<llvm::Constant>(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: 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: 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<GNUFlexibleArrayInitializer>;
 
+// 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<DuplicateDeclSpecifier>;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to