about summary refs log tree commit diff homepage
diff options
context:
space:
mode:
-rw-r--r--lib/Core/Executor.cpp53
-rw-r--r--lib/Core/Executor.h1
-rw-r--r--test/Feature/Alias.c19
3 files changed, 57 insertions, 16 deletions
diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp
index 9209be8a..3272201a 100644
--- a/lib/Core/Executor.cpp
+++ b/lib/Core/Executor.cpp
@@ -755,23 +755,46 @@ void Executor::allocateGlobalObjects(ExecutionState &state) {
   }
 }
 
-void Executor::initializeGlobalAliases() {
-  const Module *m = kmodule->module.get();
-
-  // link aliases to their definitions (if bound)
-  for (auto i = m->alias_begin(), ie = m->alias_end(); i != ie; ++i) {
-    // Map the alias to its aliasee's address. This works because we have
-    // addresses for everything, even undefined functions.
-
-    // Alias may refer to other alias, not necessarily known at this point.
-    // Thus, resolve to real alias directly.
-    const GlobalAlias *alias = &*i;
-    while (const auto *ga = dyn_cast<GlobalAlias>(alias->getAliasee())) {
-      assert(ga != alias && "alias pointing to itself");
-      alias = ga;
+void Executor::initializeGlobalAlias(const llvm::Constant *c) {
+  // aliasee may either be a global value or constant expression
+  const auto *ga = dyn_cast<GlobalAlias>(c);
+  if (ga) {
+    if (globalAddresses.count(ga)) {
+      // already resolved by previous invocation
+      return;
     }
+    const llvm::Constant *aliasee = ga->getAliasee();
+    if (const auto *gv = dyn_cast<GlobalValue>(aliasee)) {
+      // aliasee is global value
+      auto it = globalAddresses.find(gv);
+      // uninitialized only if aliasee is another global alias
+      if (it != globalAddresses.end()) {
+        globalAddresses.emplace(ga, it->second);
+        return;
+      }
+    }
+  }
+
+  // resolve aliases in all sub-expressions
+#if LLVM_VERSION_CODE >= LLVM_VERSION(4, 0)
+  for (const auto *op : c->operand_values()) {
+#else
+  for (auto &it : c->operands()) {
+    const auto *op = &*it;
+#endif
+    initializeGlobalAlias(cast<Constant>(op));
+  }
 
-    globalAddresses.insert(std::make_pair(&*i, evalConstant(alias->getAliasee())));
+  if (ga) {
+    // aliasee is constant expression (or global alias)
+    globalAddresses.emplace(ga, evalConstant(ga->getAliasee()));
+  }
+}
+
+void Executor::initializeGlobalAliases() {
+  const Module *m = kmodule->module.get();
+  for (const GlobalAlias &a : m->aliases()) {
+    initializeGlobalAlias(&a);
   }
 }
 
diff --git a/lib/Core/Executor.h b/lib/Core/Executor.h
index 61664193..7acbc60f 100644
--- a/lib/Core/Executor.h
+++ b/lib/Core/Executor.h
@@ -226,6 +226,7 @@ private:
   MemoryObject *addExternalObject(ExecutionState &state, void *addr, 
                                   unsigned size, bool isReadOnly);
 
+  void initializeGlobalAlias(const llvm::Constant *c);
   void initializeGlobalObject(ExecutionState &state, ObjectState *os, 
 			      const llvm::Constant *c,
 			      unsigned offset);
diff --git a/test/Feature/Alias.c b/test/Feature/Alias.c
index 29cc08d7..e1f58901 100644
--- a/test/Feature/Alias.c
+++ b/test/Feature/Alias.c
@@ -6,6 +6,10 @@
 
 #include <assert.h>
 
+// alias with bitcast
+// NOTE: this does not have to be before b is known
+extern short d __attribute__((alias("b")));
+
 // alias for global
 int b = 52;
 extern int a __attribute__((alias("b")));
@@ -18,13 +22,26 @@ extern int foo2() __attribute__((alias("foo")));
 int __foo() { return 52; }
 extern int foo() __attribute__((alias("__foo")));
 
+// alias without bitcast
+extern int foo3(void) __attribute__((alias("__foo")));
+
 int *c = &a;
 
 int main() {
   assert(a == 52);
+  assert(*c == 52);
+  assert((int)d == 52);
+
+  assert(c == &b);
+  assert((int*)&d != &b);
+
   assert(foo() == 52);
   assert(foo2() == 52);
-  assert(*c == 52);
+  assert(foo3() == 52);
+
+  assert(foo != __foo);
+  assert(foo2 != __foo);
+  assert(foo3 == __foo);
 
   return 0;
 }