Implemented linking to a dummy ASan runtime

BUG=https://bugs.chromium.org/p/nativeclient/issues/detail?id=4374
R=kschimpf@google.com

Review URL: https://codereview.chromium.org/2068593003 .
diff --git a/Makefile.standalone b/Makefile.standalone
index 9c10dce..201a8e4 100644
--- a/Makefile.standalone
+++ b/Makefile.standalone
@@ -501,13 +501,15 @@
 
 RT_SRC := runtime/szrt.c runtime/szrt_ll.ll runtime/szrt_profiler.c \
           runtime/szrt_asm_x8632.s runtime/szrt_asm_x8664.s \
-          runtime/szrt_asm_arm32.s
+          runtime/szrt_asm_arm32.s runtime/szrt_asan.c
 RT_OBJ := build/runtime/szrt_native_x8632.o build/runtime/szrt_sb_x8632.o \
           build/runtime/szrt_nonsfi_x8632.o \
           build/runtime/szrt_native_x8664.o build/runtime/szrt_sb_x8664.o \
           build/runtime/szrt_nonsfi_x8664.o \
           build/runtime/szrt_native_arm32.o build/runtime/szrt_sb_arm32.o \
-          build/runtime/szrt_nonsfi_arm32.o
+          build/runtime/szrt_nonsfi_arm32.o \
+          build/runtime/szrt_asan_x8632.o build/runtime/szrt_asan_x8664.o \
+          build/runtime/szrt_asan_arm32.o
 
 runtime: $(RT_OBJ)
 
diff --git a/pydir/build-runtime.py b/pydir/build-runtime.py
index cb923ba..caed297 100755
--- a/pydir/build-runtime.py
+++ b/pydir/build-runtime.py
@@ -84,6 +84,14 @@
     shellcmd([GetObjcopyCmd(),
               '--strip-symbol=NATIVE',
               OutFile('{rtdir}/szrt_native_{target}.o')])
+    # Compile srcdir/szrt_asan.c to szrt_asan_{target}.o
+    shellcmd(['clang',
+              '-O2',
+              '-target=' + target_info.triple,
+              '-c',
+              '{srcdir}/szrt_asan.c'.format(srcdir=srcdir),
+              '-o', OutFile('{rtdir}/szrt_asan_{target}.o')
+      ], echo=verbose)
 
   # Helper function for building the sandboxed runtime.
   def MakeSandboxedRuntime():
diff --git a/pydir/szbuild.py b/pydir/szbuild.py
index 558db48..7333729 100755
--- a/pydir/szbuild.py
+++ b/pydir/szbuild.py
@@ -103,6 +103,9 @@
                            default=[], help='Extra arguments for llc')
     argparser.add_argument('--no-sz', dest='nosz', action='store_true',
                            help='Run only post-Subzero build steps')
+    argparser.add_argument('--fsanitize-address', dest='asan',
+                           action='store_true',
+                           help='Instrument with AddressSanitizer')
 
 def LinkSandbox(objs, exe, target, verbose=True):
     assert target in ('x8632', 'x8664', 'arm32'), \
@@ -263,6 +266,11 @@
     args = argparser.parse_args()
     pexe = args.pexe
     exe = args.output
+    if args.asan:
+        if args.sandbox or args.nonsfi:
+            print 'Can only use AddressSanitizer with a native build'
+            exit(1)
+        args.sz_args.append('-fsanitize-address')
     ProcessPexe(args, pexe, exe)
 
 def ProcessPexe(args, pexe, exe):
@@ -446,7 +454,13 @@
     elif args.nonsfi:
         LinkNonsfi([obj_partial], exe, args.target, args.verbose)
     else:
-        LinkNative([obj_partial], exe, args.target, args.verbose)
+        objs = [obj_partial]
+        if args.asan:
+            objs.append(
+                ('{root}/toolchain_build/src/subzero/build/runtime/' +
+                 'szrt_asan_{target}.o').format(root=nacl_root,
+                                                target=args.target))
+        LinkNative(objs, exe, args.target, args.verbose)
 
     # Put the extra verbose printing at the end.
     if args.verbose and hybrid:
diff --git a/runtime/szrt_asan.c b/runtime/szrt_asan.c
new file mode 100644
index 0000000..f89f04b
--- /dev/null
+++ b/runtime/szrt_asan.c
@@ -0,0 +1,24 @@
+//===- subzero/runtime/szrt_asan.c - AddressSanitizer Runtime -----*- C -*-===//
+//
+//                        The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides the AddressSanitizer runtime.
+///
+/// Exposes functions for initializing the shadow memory region and managing it
+/// on loads, stores, and allocations.
+///
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+// TODO(tlively): Define and implement this library
+void __asan_init(void) {
+  printf("Set up shadow memory here\n");
+  return;
+}
diff --git a/src/IceASanInstrumentation.cpp b/src/IceASanInstrumentation.cpp
index 45ec038..1cda875 100644
--- a/src/IceASanInstrumentation.cpp
+++ b/src/IceASanInstrumentation.cpp
@@ -15,7 +15,9 @@
 #include "IceASanInstrumentation.h"
 
 #include "IceBuildDefs.h"
+#include "IceCfgNode.h"
 #include "IceGlobalInits.h"
+#include "IceInst.h"
 
 #include <sstream>
 
@@ -109,4 +111,15 @@
   return Rz;
 }
 
+void ASanInstrumentation::instrumentStart(Cfg *Func) {
+  Constant *ShadowMemInit =
+      Ctx->getConstantExternSym(Ctx->getGlobalString("__asan_init"));
+  constexpr SizeT NumArgs = 0;
+  constexpr Variable *Void = nullptr;
+  constexpr bool NoTailCall = false;
+
+  auto *Call = InstCall::create(Func, NumArgs, Void, ShadowMemInit, NoTailCall);
+  Func->getEntryNode()->getInsts().push_front(Call);
+}
+
 } // end of namespace Ice
diff --git a/src/IceASanInstrumentation.h b/src/IceASanInstrumentation.h
index ee20e7d..29f279d 100644
--- a/src/IceASanInstrumentation.h
+++ b/src/IceASanInstrumentation.h
@@ -40,6 +40,7 @@
                                 VariableDeclaration *RzArray,
                                 SizeT &RzArraySize,
                                 VariableDeclaration *Global);
+  void instrumentStart(Cfg *Func) override;
   bool DidInsertRedZones = false;
   uint32_t RzNum = 0;
 };
diff --git a/src/IceInstrumentation.cpp b/src/IceInstrumentation.cpp
index 0d56100..fc2a4a5 100644
--- a/src/IceInstrumentation.cpp
+++ b/src/IceInstrumentation.cpp
@@ -41,6 +41,9 @@
       Context.advanceNext();
     }
   }
+
+  if (Func->getFunctionName().toStringOrEmpty() == "_start")
+    instrumentStart(Func);
 }
 
 void Instrumentation::instrumentInst(LoweringContext &Context) {
diff --git a/src/IceInstrumentation.h b/src/IceInstrumentation.h
index a7e099b..8b7e2e7 100644
--- a/src/IceInstrumentation.h
+++ b/src/IceInstrumentation.h
@@ -69,6 +69,7 @@
   virtual void instrumentSwitch(LoweringContext &, const class InstSwitch *) {}
   virtual void instrumentUnreachable(LoweringContext &,
                                      const class InstUnreachable *) {}
+  virtual void instrumentStart(Cfg *) {}
   virtual void instrumentLocalVars(Cfg *) {}
 
 protected:
diff --git a/tests_lit/asan_tests/globalredzones.ll b/tests_lit/asan_tests/globalredzones.ll
index a4052e7..623ce60 100644
--- a/tests_lit/asan_tests/globalredzones.ll
+++ b/tests_lit/asan_tests/globalredzones.ll
@@ -3,9 +3,9 @@
 ; REQUIRES: allow_dump
 
 ; RUN: %p2i -i %s --args -threads=0 -fsanitize-address \
-; RUN:     | %iflc FileCheck %s
+; RUN:     | FileCheck %s
 ; RUN: %p2i -i %s --args -verbose=global_init,inst -threads=0 \
-; RUN:     -fsanitize-address | %iflc FileCheck --check-prefix=DUMP %s
+; RUN:     -fsanitize-address | FileCheck --check-prefix=DUMP %s
 
 ; The array of redzones
 
diff --git a/tests_lit/asan_tests/startinitcall.ll b/tests_lit/asan_tests/startinitcall.ll
new file mode 100644
index 0000000..2a1a7a3
--- /dev/null
+++ b/tests_lit/asan_tests/startinitcall.ll
@@ -0,0 +1,28 @@
+; Test for a call to __asan_init in _start
+
+; REQUIRES: allow_dump
+
+; RUN: %p2i -i %s --args -verbose=inst -threads=0 -fsanitize-address \
+; RUN:     | FileCheck --check-prefix=DUMP %s
+
+; notStart() should not be instrumented
+define internal void @notStart() {
+  ret void
+}
+
+; DUMP-LABEL: define internal void @notStart() { # notStart(i=1:b=1)
+; DUMP-NEXT: __0:
+; DUMP-NOT: __asan_init()
+; DUMP: ret void
+; DUMP-NEXT: }
+
+; _start() should be instrumented
+define void @_start() {
+  ret void
+}
+
+; DUMP-LABEL: define void @_start() { # _start(i=2:b=1)
+; DUMP-NEXT: __0:
+; DUMP-NEXT: call void @__asan_init()
+; DUMP-NEXT: ret void
+; DUMP-NEXT: }