Merge "CTS: allow continue to use the old AIDs on devices launch with P"
diff --git a/libc/arch-common/bionic/crtbrand.S b/libc/arch-common/bionic/crtbrand.S
index 4b4f99c..34d6480 100644
--- a/libc/arch-common/bionic/crtbrand.S
+++ b/libc/arch-common/bionic/crtbrand.S
@@ -33,7 +33,12 @@
   .long 2f-1f                 // int32_t namesz
   .long 3f-2f                 // int32_t descsz
   .long 1                     // int32_t type
+#ifdef __ANDROID__
 1:.ascii "Android\0"          // char name[]
 2:.long PLATFORM_SDK_VERSION  // int32_t android_api
+#else
+1:.ascii "LinuxBionic\0"      // char name[]
+2:
+#endif
 3:
   .size abitag, .-abitag
diff --git a/libc/bionic/jemalloc_wrapper.cpp b/libc/bionic/jemalloc_wrapper.cpp
index 812884c..40f2a66 100644
--- a/libc/bionic/jemalloc_wrapper.cpp
+++ b/libc/bionic/jemalloc_wrapper.cpp
@@ -79,6 +79,18 @@
       }
     }
     return 1;
+  } else if (param == M_PURGE) {
+    unsigned narenas;
+    size_t sz = sizeof(unsigned);
+    if (je_mallctl("arenas.narenas", &narenas, &sz, nullptr, 0) != 0) {
+      return 0;
+    }
+    char buffer[100];
+    snprintf(buffer, sizeof(buffer), "arena.%u.purge", narenas);
+    if (je_mallctl(buffer, nullptr, nullptr, nullptr, 0) != 0) {
+      return 0;
+    }
+    return 1;
   }
   return 0;
 }
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index f5fbedf..58a9b1d 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -163,6 +163,7 @@
 
 /** mallopt() option to set the decay time. Valid values are 0 and 1. */
 #define M_DECAY_TIME -100
+#define M_PURGE -101
 
 /**
  * [mallopt(3)](http://man7.org/linux/man-pages/man3/mallopt.3.html) modifies
diff --git a/linker/linker.cpp b/linker/linker.cpp
index b605ed9..f085863 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1318,6 +1318,15 @@
     }
   }
 
+#if !defined(__ANDROID__)
+  // Bionic on the host currently uses some Android prebuilts, which don't set
+  // DT_RUNPATH with any relative paths, so they can't find their dependencies.
+  // b/118058804
+  if (si->get_dt_runpath().empty()) {
+    si->set_dt_runpath("$ORIGIN/../lib64:$ORIGIN/lib64");
+  }
+#endif
+
   for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
     load_tasks->push_back(LoadTask::create(name, si, ns, task->get_readers_map()));
   });
diff --git a/linker/linker_wrapper.cpp b/linker/linker_wrapper.cpp
index 571d3ab..fc673aa 100644
--- a/linker/linker_wrapper.cpp
+++ b/linker/linker_wrapper.cpp
@@ -28,9 +28,27 @@
 
 #include "private/KernelArgumentBlock.h"
 
-extern const char linker_code_start;
-extern const char original_start;
-extern const char linker_entry;
+extern const char linker_offset;
+
+// This will be replaced by host_bionic_inject, but must be non-zero
+// here so that it's placed in the data section.
+uintptr_t original_start = 42;
+
+/* Find the load bias and base address of an executable or shared object loaded
+ * by the kernel. The ELF file's PHDR table must have a PT_PHDR entry.
+ *
+ * A VDSO doesn't have a PT_PHDR entry in its PHDR table.
+ */
+static void get_elf_base_from_phdr(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                                   ElfW(Addr)* base, ElfW(Addr)* load_bias) {
+  for (size_t i = 0; i < phdr_count; ++i) {
+    if (phdr_table[i].p_type == PT_PHDR) {
+      *load_bias = reinterpret_cast<ElfW(Addr)>(phdr_table) - phdr_table[i].p_vaddr;
+      *base = reinterpret_cast<ElfW(Addr)>(phdr_table) - phdr_table[i].p_offset;
+      return;
+    }
+  }
+}
 
 /*
  * This is the entry point for the linker wrapper, which finds
@@ -39,21 +57,26 @@
 extern "C" ElfW(Addr) __linker_init(void* raw_args) {
   KernelArgumentBlock args(raw_args);
 
-  static uintptr_t linker_offset = reinterpret_cast<uintptr_t>(&linker_code_start);
-  static uintptr_t linktime_addr = reinterpret_cast<uintptr_t>(&linktime_addr);
-  ElfW(Addr) my_addr = reinterpret_cast<uintptr_t>(&linktime_addr) - linktime_addr;
+  ElfW(Addr) base_addr = 0;
+  ElfW(Addr) load_bias = 0;
+  get_elf_base_from_phdr(
+    reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR)), args.getauxval(AT_PHNUM),
+    &base_addr, &load_bias);
 
-  // Set AT_ENTRY to the proper entry point
+  ElfW(Addr) linker_addr = base_addr + reinterpret_cast<uintptr_t>(&linker_offset);
+  ElfW(Addr) linker_entry_offset = reinterpret_cast<ElfW(Ehdr)*>(linker_addr)->e_entry;
+
   for (ElfW(auxv_t)* v = args.auxv; v->a_type != AT_NULL; ++v) {
     if (v->a_type == AT_BASE) {
-      v->a_un.a_val = my_addr + linker_offset;
+      // Set AT_BASE to the embedded linker
+      v->a_un.a_val = linker_addr;
     }
     if (v->a_type == AT_ENTRY) {
-      v->a_un.a_val = my_addr + reinterpret_cast<uintptr_t>(&original_start);
+      // Set AT_ENTRY to the proper entry point
+      v->a_un.a_val = base_addr + original_start;
     }
   }
 
-  // Return address of linker entry point -- may need to ensure that raw_args
-  // was saved.
-  return my_addr + linker_offset + reinterpret_cast<uintptr_t>(&linker_entry);
+  // Return address of linker entry point
+  return linker_addr + linker_entry_offset;
 }