Clang driver support for linking on Android.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@155541 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 1008b63..b61b8dc 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1269,22 +1269,33 @@
 /// This needs to be called before we add the C run-time (malloc, etc).
 static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args,
                            ArgStringList &CmdArgs) {
-  // Add asan linker flags when linking an executable, but not a shared object.
-  if (Args.hasArg(options::OPT_shared) ||
-      !Args.hasFlag(options::OPT_faddress_sanitizer,
+  if (!Args.hasFlag(options::OPT_faddress_sanitizer,
                     options::OPT_fno_address_sanitizer, false))
     return;
+  if(TC.getTriple().getEnvironment() == llvm::Triple::ANDROIDEABI) {
+    if (!Args.hasArg(options::OPT_shared)) {
+      // For an executable, we add a .preinit_array stub.
+      CmdArgs.push_back("-u");
+      CmdArgs.push_back("__asan_preinit");
+      CmdArgs.push_back("-lasan");
+    }
 
-  // LibAsan is "libclang_rt.asan-<ArchName>.a" in the Linux library resource
-  // directory.
-  SmallString<128> LibAsan(TC.getDriver().ResourceDir);
-  llvm::sys::path::append(LibAsan, "lib", "linux",
-                          (Twine("libclang_rt.asan-") +
-                           TC.getArchName() + ".a"));
-  CmdArgs.push_back(Args.MakeArgString(LibAsan));
-  CmdArgs.push_back("-lpthread");
-  CmdArgs.push_back("-ldl");
-  CmdArgs.push_back("-export-dynamic");
+    CmdArgs.push_back("-lasan_preload");
+    CmdArgs.push_back("-ldl");
+  } else {
+    if (!Args.hasArg(options::OPT_shared)) {
+      // LibAsan is "libclang_rt.asan-<ArchName>.a" in the Linux library
+      // resource directory.
+      SmallString<128> LibAsan(TC.getDriver().ResourceDir);
+      llvm::sys::path::append(LibAsan, "lib", "linux",
+                              (Twine("libclang_rt.asan-") +
+                               TC.getArchName() + ".a"));
+      CmdArgs.push_back(Args.MakeArgString(LibAsan));
+      CmdArgs.push_back("-lpthread");
+      CmdArgs.push_back("-ldl");
+      CmdArgs.push_back("-export-dynamic");
+    }
+  }
 }
 
 static bool shouldUseFramePointer(const ArgList &Args,
@@ -5116,9 +5127,10 @@
   C.addCommand(new Command(JA, *this, Exec, CmdArgs));
 }
 
-static void AddLibgcc(const Driver &D, ArgStringList &CmdArgs,
-                      const ArgList &Args) {
-  bool StaticLibgcc = Args.hasArg(options::OPT_static) ||
+static void AddLibgcc(llvm::Triple Triple, const Driver &D,
+                      ArgStringList &CmdArgs, const ArgList &Args) {
+  bool isAndroid = Triple.getEnvironment() == llvm::Triple::ANDROIDEABI;
+  bool StaticLibgcc = isAndroid || Args.hasArg(options::OPT_static) ||
     Args.hasArg(options::OPT_static_libgcc);
   if (!D.CCCIsCXX)
     CmdArgs.push_back("-lgcc");
@@ -5134,7 +5146,7 @@
       CmdArgs.push_back("--no-as-needed");
   }
 
-  if (StaticLibgcc)
+  if (StaticLibgcc && !isAndroid)
     CmdArgs.push_back("-lgcc_eh");
   else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX)
     CmdArgs.push_back("-lgcc");
@@ -5148,6 +5160,9 @@
   const toolchains::Linux& ToolChain =
     static_cast<const toolchains::Linux&>(getToolChain());
   const Driver &D = ToolChain.getDriver();
+  const bool isAndroid = ToolChain.getTriple().getEnvironment() ==
+    llvm::Triple::ANDROIDEABI;
+
   ArgStringList CmdArgs;
 
   // Silence warning for "clang -g foo.o -o foo"
@@ -5208,6 +5223,10 @@
       CmdArgs.push_back("-static");
   } else if (Args.hasArg(options::OPT_shared)) {
     CmdArgs.push_back("-shared");
+    if ((ToolChain.getArch() == llvm::Triple::arm
+         || ToolChain.getArch() == llvm::Triple::thumb) && isAndroid) {
+      CmdArgs.push_back("-Bsymbolic");
+    }
   }
 
   if (ToolChain.getArch() == llvm::Triple::arm ||
@@ -5215,7 +5234,9 @@
       (!Args.hasArg(options::OPT_static) &&
        !Args.hasArg(options::OPT_shared))) {
     CmdArgs.push_back("-dynamic-linker");
-    if (ToolChain.getArch() == llvm::Triple::x86)
+    if (isAndroid)
+      CmdArgs.push_back("/system/bin/linker");
+    else if (ToolChain.getArch() == llvm::Triple::x86)
       CmdArgs.push_back("/lib/ld-linux.so.2");
     else if (ToolChain.getArch() == llvm::Triple::arm ||
              ToolChain.getArch() == llvm::Triple::thumb)
@@ -5239,25 +5260,27 @@
 
   if (!Args.hasArg(options::OPT_nostdlib) &&
       !Args.hasArg(options::OPT_nostartfiles)) {
-    const char *crt1 = NULL;
-    if (!Args.hasArg(options::OPT_shared)){
-      if (Args.hasArg(options::OPT_pie))
-        crt1 = "Scrt1.o";
-      else
-        crt1 = "crt1.o";
-    }
-    if (crt1)
-      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));
+    if (!isAndroid) {
+      const char *crt1 = NULL;
+      if (!Args.hasArg(options::OPT_shared)){
+        if (Args.hasArg(options::OPT_pie))
+          crt1 = "Scrt1.o";
+        else
+          crt1 = "crt1.o";
+      }
+      if (crt1)
+        CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));
 
-    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+    }
 
     const char *crtbegin;
     if (Args.hasArg(options::OPT_static))
-      crtbegin = "crtbeginT.o";
+      crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o";
     else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
-      crtbegin = "crtbeginS.o";
+      crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o";
     else
-      crtbegin = "crtbegin.o";
+      crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o";
     CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
   }
 
@@ -5298,7 +5321,7 @@
     if (Args.hasArg(options::OPT_static))
       CmdArgs.push_back("--start-group");
 
-    AddLibgcc(D, CmdArgs, Args);
+    AddLibgcc(ToolChain.getTriple(), D, CmdArgs, Args);
 
     if (Args.hasArg(options::OPT_pthread) ||
         Args.hasArg(options::OPT_pthreads))
@@ -5309,18 +5332,19 @@
     if (Args.hasArg(options::OPT_static))
       CmdArgs.push_back("--end-group");
     else
-      AddLibgcc(D, CmdArgs, Args);
+      AddLibgcc(ToolChain.getTriple(), D, CmdArgs, Args);
 
 
     if (!Args.hasArg(options::OPT_nostartfiles)) {
       const char *crtend;
       if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
-        crtend = "crtendS.o";
+        crtend = isAndroid ? "crtend_so.o" : "crtendS.o";
       else
-        crtend = "crtend.o";
+        crtend = isAndroid ? "crtend_android.o" : "crtend.o";
 
       CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
-      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
+      if (!isAndroid)
+        CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
     }
   }
 
diff --git a/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_dynamic.o b/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_dynamic.o
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_dynamic.o
diff --git a/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_so.o b/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_so.o
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_so.o
diff --git a/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_static.o b/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_static.o
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_static.o
diff --git a/test/Driver/Inputs/basic_android_tree/usr/lib/crtend_android.o b/test/Driver/Inputs/basic_android_tree/usr/lib/crtend_android.o
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/usr/lib/crtend_android.o
diff --git a/test/Driver/Inputs/basic_android_tree/usr/lib/crtend_so.o b/test/Driver/Inputs/basic_android_tree/usr/lib/crtend_so.o
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/usr/lib/crtend_so.o
diff --git a/test/Driver/asan-ld.c b/test/Driver/asan-ld.c
new file mode 100644
index 0000000..feb8e21
--- /dev/null
+++ b/test/Driver/asan-ld.c
@@ -0,0 +1,31 @@
+// Test AddressSanitizer ld flags.
+
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN:     -target i386-unknown-linux -faddress-sanitizer \
+// RUN:     --sysroot=%S/Inputs/basic_linux_tree \
+// RUN:   | FileCheck --check-prefix=CHECK-LINUX %s
+// CHECK-LINUX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-LINUX-NOT: "-lc"
+// CHECK-LINUX: lib/linux/libclang_rt.asan-i386.a"
+// CHECK-LINUX: "-lpthread"
+// CHECK-LINUX: "-ldl"
+// CHECK-LINUX: "-export-dynamic"
+
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN:     -target arm-linux-androideabi -faddress-sanitizer \
+// RUN:     --sysroot=%S/Inputs/basic_android_tree \
+// RUN:   | FileCheck --check-prefix=CHECK-ANDROID %s
+// CHECK-ANDROID: "{{.*}}ld{{(.exe)?}}"
+// CHECK-ANDROID-NOT: "-lc"
+// CHECK-ANDROID: "-u" "__asan_preinit" "-lasan"
+// CHECK-ANDROID: "-lasan_preload" "-ldl"
+
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN:     -target arm-linux-androideabi -faddress-sanitizer \
+// RUN:     --sysroot=%S/Inputs/basic_android_tree \
+// RUN:     -shared \
+// RUN:   | FileCheck --check-prefix=CHECK-ANDROID-SHARED %s
+// CHECK-ANDROID-SHARED: "{{.*}}ld{{(.exe)?}}"
+// CHECK-ANDROID-SHARED-NOT: "-lc"
+// CHECK-ANDROID-SHARED-NOT: "-lasan"
+// CHECK-ANDROID-SHARED: "-lasan_preload" "-ldl"
diff --git a/test/Driver/linux-ld.c b/test/Driver/linux-ld.c
index 9a35d5d..3d6a7e6 100644
--- a/test/Driver/linux-ld.c
+++ b/test/Driver/linux-ld.c
@@ -268,3 +268,39 @@
 // CHECK-DEBIAN-PPC64: "-L[[SYSROOT]]/lib"
 // CHECK-DEBIAN-PPC64: "-L[[SYSROOT]]/usr/lib"
 //
+// Test linker invocation on Android.
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN:     -target arm-linux-androideabi \
+// RUN:     --sysroot=%S/Inputs/basic_android_tree \
+// RUN:   | FileCheck --check-prefix=CHECK-ANDROID %s
+// CHECK-ANDROID: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-ANDROID: "{{.*}}/crtbegin_dynamic.o"
+// CHECK-ANDROID: "-L[[SYSROOT]]/usr/lib"
+// CHECK-ANDROID-NOT: "gcc_s"
+// CHECK-ANDROID: "-lgcc"
+// CHECK-ANDROID-NOT: "gcc_s"
+// CHECK-ANDROID: "{{.*}}/crtend_android.o"
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN:     -target arm-linux-androideabi \
+// RUN:     --sysroot=%S/Inputs/basic_android_tree \
+// RUN:     -shared \
+// RUN:   | FileCheck --check-prefix=CHECK-ANDROID-SO %s
+// CHECK-ANDROID-SO: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-ANDROID-SO: "{{.*}}/crtbegin_so.o"
+// CHECK-ANDROID-SO: "-L[[SYSROOT]]/usr/lib"
+// CHECK-ANDROID-SO-NOT: "gcc_s"
+// CHECK-ANDROID-SO: "-lgcc"
+// CHECK-ANDROID-SO-NOT: "gcc_s"
+// CHECK-ANDROID-SO: "{{.*}}/crtend_so.o"
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN:     -target arm-linux-androideabi \
+// RUN:     --sysroot=%S/Inputs/basic_android_tree \
+// RUN:     -static \
+// RUN:   | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
+// CHECK-ANDROID-STATIC: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-ANDROID-STATIC: "{{.*}}/crtbegin_static.o"
+// CHECK-ANDROID-STATIC: "-L[[SYSROOT]]/usr/lib"
+// CHECK-ANDROID-STATIC-NOT: "gcc_s"
+// CHECK-ANDROID-STATIC: "-lgcc"
+// CHECK-ANDROID-STATIC-NOT: "gcc_s"
+// CHECK-ANDROID-STATIC: "{{.*}}/crtend_android.o"