diff options
-rw-r--r-- | lib/Core/Executor.cpp | 53 | ||||
-rw-r--r-- | lib/Core/Executor.h | 1 | ||||
-rw-r--r-- | test/Feature/Alias.c | 19 |
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; } |