Let executables not rely on sentinels in preinit_array/init_array/fini_array

Currently, we use sentinels (starting with -1 and ending with 0) in
preinit_array/init_array/fini_array in executables. But after using LTO,
the sentinels can be reordered by LLD and no longer work. So make below
changes to not rely on them:
  1. In crtbegin.c, use symbols (like __init_array_start) inserted by the
     linker.
  2. Add array_count fields in structors_array_t.
  3. In static libc, use array_count fields to decide array lengths.
  4. To make new dynamic executables work with old libc.so, create a fake
     fini_array with sentinels, and pass it to __libc_init. The fake
     fini_array contains a function to call functions in real fini_array.
  5. To make old dynamic executables work with new libc.so, libc.so
     still uses sentinels to decide the length of fini_array.

Bug: 295944813
Bug: https://github.com/android/ndk/issues/1461
Test: run bionic-unit-tests-static
Test: test static executables manually
Test: boot cf_gwear_x86-trunk_staging-userdebug
Change-Id: I1ce31f07bcfe0e99b4237984898a8fc9e98ff426
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index a3c66d4..1591785 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -69,10 +69,21 @@
 extern "C" int __cxa_atexit(void (*)(void *), void *, void *);
 extern "C" const char* __gnu_basename(const char* path);
 
-static void call_array(init_func_t** list, int argc, char* argv[], char* envp[]) {
-  // First element is -1, list is null-terminated
-  while (*++list) {
-    (*list)(argc, argv, envp);
+static void call_array(init_func_t** list, size_t count, int argc, char* argv[], char* envp[]) {
+  while (count-- > 0) {
+    init_func_t* function = *list++;
+    (*function)(argc, argv, envp);
+  }
+}
+
+static void call_fini_array(void* arg) {
+  structors_array_t* structors = reinterpret_cast<structors_array_t*>(arg);
+  fini_func_t** array = structors->fini_array;
+  size_t count = structors->fini_array_count;
+  // Now call each destructor in reverse order.
+  while (count-- > 0) {
+    fini_func_t* function = array[count];
+    (*function)();
   }
 }
 
@@ -413,14 +424,15 @@
   // Several Linux ABIs don't pass the onexit pointer, and the ones that
   // do never use it.  Therefore, we ignore it.
 
-  call_array(structors->preinit_array, args.argc, args.argv, args.envp);
-  call_array(structors->init_array, args.argc, args.argv, args.envp);
+  call_array(structors->preinit_array, structors->preinit_array_count, args.argc, args.argv,
+             args.envp);
+  call_array(structors->init_array, structors->init_array_count, args.argc, args.argv, args.envp);
 
   // The executable may have its own destructors listed in its .fini_array
   // so we need to ensure that these are called when the program exits
   // normally.
-  if (structors->fini_array != nullptr) {
-    __cxa_atexit(__libc_fini,structors->fini_array,nullptr);
+  if (structors->fini_array_count > 0) {
+    __cxa_atexit(call_fini_array, const_cast<structors_array_t*>(structors), nullptr);
   }
 
   __libc_init_mte_late();