linker: Add library load and unload hooks for HWASan.

These hooks notify the HWASan runtime library whenever a library is loaded
or unloaded so that it can update its shadow memory.

Bug: 138159093
Test: walleye_hwasan-userdebug boots with+without https://reviews.llvm.org/D65770
Change-Id: I6caf2a6540ed2c0d94db444e806a3c7ba504cabb
diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
index 4f3b4f7..d6d5552 100644
--- a/libc/bionic/libc_init_dynamic.cpp
+++ b/libc/bionic/libc_init_dynamic.cpp
@@ -69,6 +69,13 @@
 __LIBC_HIDDEN__ void* __libc_sysinfo = reinterpret_cast<void*>(__libc_int0x80);
 #endif
 
+extern "C" __attribute__((weak)) void __hwasan_library_loaded(ElfW(Addr) base,
+                                                              const ElfW(Phdr)* phdr,
+                                                              ElfW(Half) phnum);
+extern "C" __attribute__((weak)) void __hwasan_library_unloaded(ElfW(Addr) base,
+                                                                const ElfW(Phdr)* phdr,
+                                                                ElfW(Half) phnum);
+
 // We need a helper function for __libc_preinit because compiling with LTO may
 // inline functions requiring a stack protector check, but __stack_chk_guard is
 // not initialized at the start of __libc_preinit. __libc_preinit_impl will run
@@ -91,6 +98,14 @@
 
   // Hooks for various libraries to let them know that we're starting up.
   __libc_globals.mutate(__libc_init_malloc);
+
+#if __has_feature(hwaddress_sanitizer)
+  // Notify the HWASan runtime library whenever a library is loaded or unloaded
+  // so that it can update its shadow memory.
+  __libc_shared_globals()->load_hook = __hwasan_library_loaded;
+  __libc_shared_globals()->unload_hook = __hwasan_library_unloaded;
+#endif
+
   netdClientInit();
 }
 
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index d73079e..ef735ba 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -88,6 +88,10 @@
   TlsModules tls_modules;
   BionicAllocator tls_allocator;
 
+  // Values passed from the HWASan runtime (via libc.so) to the loader.
+  void (*load_hook)(ElfW(Addr) base, const ElfW(Phdr)* phdr, ElfW(Half) phnum) = nullptr;
+  void (*unload_hook)(ElfW(Addr) base, const ElfW(Phdr)* phdr, ElfW(Half) phnum) = nullptr;
+
   // Values passed from the linker to libc.so.
   const char* init_progname = nullptr;
   char** init_environ = nullptr;
diff --git a/linker/linker.cpp b/linker/linker.cpp
index df7dd40..0361a8a 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1905,6 +1905,9 @@
             !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
           return false;
         }
+        if (__libc_shared_globals()->load_hook) {
+          __libc_shared_globals()->load_hook(si->load_bias, si->phdr, si->phnum);
+        }
       }
 
       return true;
@@ -2039,6 +2042,9 @@
            si);
     notify_gdb_of_unload(si);
     unregister_soinfo_tls(si);
+    if (__libc_shared_globals()->unload_hook) {
+      __libc_shared_globals()->unload_hook(si->load_bias, si->phdr, si->phnum);
+    }
     get_cfi_shadow()->BeforeUnload(si);
     soinfo_free(si);
   }