Fix a few bionic test failures caused by hwasan global instrumentation.

The call to the load hook needs to be moved before the call to link_image()
because the latter calls ifunc resolvers which might access global
variables. This fixes a bunch of ifunc tests.

The dlfcn.segment_gap test is currently failing. One problem is that the name
of the .bss.end_of_gap section changes as a result of global instrumentation.
Add some wildcards in so that we match both names. The other problem seems
to be the same as b/139089152.

It turns out that we need to untag pointers in a few more places. Since we have
quite a few of these now it seems worth creating a function for it.

Test: bionic-unit-tests
Change-Id: I44e2b0904faacdda7cc0c5e844ffc09de01dea2d
diff --git a/libc/private/WriteProtected.h b/libc/private/WriteProtected.h
index d240e14..26c239c 100644
--- a/libc/private/WriteProtected.h
+++ b/libc/private/WriteProtected.h
@@ -47,11 +47,11 @@
   WriteProtectedContents<T> contents;
 
   int set_protection(int prot) {
-    auto addr = reinterpret_cast<uintptr_t>(&contents);
+    auto addr = &contents;
 #if __has_feature(hwaddress_sanitizer)
     // The mprotect system call does not currently untag pointers, so do it
     // ourselves.
-    addr &= (1ULL << 56) - 1;
+    addr = untag_address(addr);
 #endif
     return mprotect(reinterpret_cast<void*>(addr), PAGE_SIZE, prot);
   }
diff --git a/libc/private/bionic_macros.h b/libc/private/bionic_macros.h
index 4800e3a..13934e5 100644
--- a/libc/private/bionic_macros.h
+++ b/libc/private/bionic_macros.h
@@ -87,3 +87,12 @@
 #else
 #define __BIONIC_FALLTHROUGH
 #endif
+
+template <typename T>
+static inline T* untag_address(T* p) {
+#if defined(__aarch64__)
+  return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(p) & ((1ULL << 56) - 1));
+#else
+  return p;
+#endif
+}
diff --git a/libdl/libdl_cfi.cpp b/libdl/libdl_cfi.cpp
index 1446143..3b68fc7 100644
--- a/libdl/libdl_cfi.cpp
+++ b/libdl/libdl_cfi.cpp
@@ -44,11 +44,8 @@
 }
 
 static uint16_t shadow_load(void* p) {
-  uintptr_t addr = reinterpret_cast<uintptr_t>(p);
-#ifdef __aarch64__
   // Untag the pointer to move it into the address space covered by the shadow.
-  addr &= (1ULL << 56) - 1;
-#endif
+  uintptr_t addr = reinterpret_cast<uintptr_t>(untag_address(p));
   uintptr_t ofs = CFIShadow::MemToShadowOffset(addr);
   if (ofs > CFIShadow::kShadowSize) return CFIShadow::kInvalidShadow;
   return *reinterpret_cast<uint16_t*>(shadow_base_storage.v + ofs);
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 0361a8a..e41194d 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -951,7 +951,9 @@
 }
 
 soinfo* find_containing_library(const void* p) {
-  ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
+  // Addresses within a library may be tagged if they point to globals. Untag
+  // them so that the bounds check succeeds.
+  ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(untag_address(p));
   for (soinfo* si = solist_get_head(); si != nullptr; si = si->next) {
     if (address < si->base || address - si->base >= si->size) {
       continue;
@@ -1901,13 +1903,13 @@
           // flag is set.
           link_extinfo = extinfo;
         }
+        if (__libc_shared_globals()->load_hook) {
+          __libc_shared_globals()->load_hook(si->load_bias, si->phdr, si->phnum);
+        }
         if (!si->link_image(global_group, local_group, link_extinfo, &relro_fd_offset) ||
             !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;
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 59cf2f7..e7274f7 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -361,8 +361,10 @@
 
   uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
   ASSERT_DL_NOTNULL(taxicab_number);
-  EXPECT_GE(reinterpret_cast<void*>(taxicab_number), start);
-  EXPECT_LT(reinterpret_cast<void*>(taxicab_number), reinterpret_cast<char*>(start) + kLibSize);
+  // Untag the pointer so that it can be compared with start, which will be untagged.
+  void* addr = reinterpret_cast<void*>(untag_address(taxicab_number));
+  EXPECT_GE(addr, start);
+  EXPECT_LT(addr, reinterpret_cast<char*>(start) + kLibSize);
   EXPECT_EQ(1729U, *taxicab_number);
 }
 
diff --git a/tests/libs/segment_gap_outer.lds b/tests/libs/segment_gap_outer.lds
index f326aab..c2961b2 100644
--- a/tests/libs/segment_gap_outer.lds
+++ b/tests/libs/segment_gap_outer.lds
@@ -22,6 +22,6 @@
   # Place end_of_gap at the end of the gap.
   . = 0x1000000;
   .bss.end_of_gap : {
-    *(.bss.end_of_gap);
+    *(.bss.*end_of_gap*);
   }
 }