Resolve MSan symbols dynamically

Runtime symbols referenced by MemorySanitizer instrumentation (e.g.
__msan_warning_noreturn) reside in the executable and are exported from
it (i.e. __attribute__((visibility("default"))). They can be
resolved using dlsym(RTLD_DEFAULT). This works for either an executable
or shared library using Reactor.

Note that this differs from our regular symbol Resolver approach which
lists pairs of symbol names and addresses. There is no public header
which declares these MSan symbols, and if we list symbols only available
in a newer version of LLVM's compiler-rt, the executable won't link or
the shared library won't load.

This change has no effect at this point. A later change will enable
MemorySanitizer intrumentation for Reactor routines.

Bug: b/155148722
Change-Id: I4601e499a2bf7073dbdd68679b74518500ebe217
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/49848
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Reactor/LLVMJIT.cpp b/src/Reactor/LLVMJIT.cpp
index 19659fe..36c85e8 100644
--- a/src/Reactor/LLVMJIT.cpp
+++ b/src/Reactor/LLVMJIT.cpp
@@ -44,14 +44,16 @@
 extern "C" void _chkstk();
 #endif
 
-#if __has_feature(memory_sanitizer)
-#	include <sanitizer/msan_interface.h>
-#endif
-
 #ifdef __ARM_EABI__
 extern "C" signed __aeabi_idivmod();
 #endif
 
+#if __has_feature(memory_sanitizer)
+#	include "sanitizer/msan_interface.h"  // TODO(b/155148722): Remove when we no longer unpoison all writes.
+
+#	include <dlfcn.h>  // dlsym()
+#endif
+
 namespace {
 
 // JITGlobals is a singleton that holds all the immutable machine specific
@@ -320,6 +322,7 @@
 		return sync_fetch_and_op(ptr, val, [](uint32_t a, uint32_t b) { return std::min(a, b); });
 	}
 #endif
+
 	class Resolver
 	{
 	public:
@@ -412,7 +415,7 @@
 			functions.try_emplace("sync_fetch_and_umin_4", reinterpret_cast<void *>(sync_fetch_and_umin_4));
 #endif
 #if __has_feature(memory_sanitizer)
-			functions.try_emplace("msan_unpoison", reinterpret_cast<void *>(__msan_unpoison));
+			functions.try_emplace("msan_unpoison", reinterpret_cast<void *>(__msan_unpoison));  // TODO(b/155148722): Remove when we no longer unpoison all writes.
 #endif
 		}
 	};
@@ -448,22 +451,41 @@
 				symbols[name] = llvm::JITEvaluatedSymbol(
 				    static_cast<llvm::JITTargetAddress>(reinterpret_cast<uintptr_t>(it->second)),
 				    llvm::JITSymbolFlags::Exported);
+
+				continue;
 			}
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
-			else
+
+#if __has_feature(memory_sanitizer)
+			// MemorySanitizer uses a dynamically linked runtime. Instrumented routines reference
+			// some symbols from this library. Look them up dynamically in the default namespace.
+			// Note this approach should not be used for other symbols, since they might not be
+			// visible (e.g. due to static linking), we may wish to provide an alternate
+			// implementation, and/or it would be a security vulnerability.
+
+			void *address = dlsym(RTLD_DEFAULT, (*symbol.first).data());
+
+			if(address)
 			{
-				missing += (missing.empty() ? "'" : ", '") + (*name).str() + "'";
+				symbols[name] = llvm::JITEvaluatedSymbol(
+				    static_cast<llvm::JITTargetAddress>(reinterpret_cast<uintptr_t>(address)),
+				    llvm::JITSymbolFlags::Exported);
+
+				continue;
 			}
-#endif  // !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#endif
+
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+			missing += (missing.empty() ? "'" : ", '") + (*name).str() + "'";
+#endif
 		}
 
 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
-		// Missing functions will likely make the module fail in exciting non-obvious ways.
+		// Missing functions will likely make the module fail in non-obvious ways.
 		if(!missing.empty())
 		{
 			WARN("Missing external functions: %s", missing.c_str());
 		}
-#endif  // !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#endif
 
 		if(symbols.empty())
 		{