linker: avoid -O0 memset while clearing temp_tcb

With -O0, on arm64, Clang uses memset for this declaration:

    bionic_tcb temp_tcb = {};

arm64 doesn't currently have an ifunc for memset, but if it did, then this
line would crash when the linker is compiled with -O0. It looks like other
architectures would only use a memset call if the bionic_tcb struct were
larger.

Avoid memset by using a custom memclr function that the compiler optimizes
into something efficient.

Also add __attribute__((uninitialized)) to ensure that
-ftrivial-auto-var-init does not generate a call to memset. See this
change[1] in build/soong.

[1] If085ec53c619e2cebc86ca23f7039298160d99ae

Test: build linker with -O0, linker[64] --help works
Bug: none
Change-Id: I0df8065a362646de4fa021cae63a7d68ca3966b6
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 264923f..8ba947f 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -593,6 +593,13 @@
 }
 #endif
 
+// Usable before ifunc resolvers have been called. This function is compiled with -ffreestanding.
+static void linker_memclr(void* dst, size_t cnt) {
+  for (size_t i = 0; i < cnt; ++i) {
+    reinterpret_cast<char*>(dst)[i] = '\0';
+  }
+}
+
 // Detect an attempt to run the linker on itself. e.g.:
 //   /system/bin/linker64 /system/bin/linker64
 // Use priority-1 to run this constructor before other constructors.
@@ -626,7 +633,8 @@
 extern "C" ElfW(Addr) __linker_init(void* raw_args) {
   // Initialize TLS early so system calls and errno work.
   KernelArgumentBlock args(raw_args);
-  bionic_tcb temp_tcb = {};
+  bionic_tcb temp_tcb __attribute__((uninitialized));
+  linker_memclr(&temp_tcb, sizeof(temp_tcb));
   __libc_init_main_thread_early(args, &temp_tcb);
 
   // When the linker is run by itself (rather than as an interpreter for