[libcxx-commits] [PATCH] D68971: [libunwind][Android] Improve workaround for PIE zero-dlpi_addr bug

Ryan Prichard via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Tue Oct 15 00:36:27 PDT 2019


rprichard created this revision.
Herald added subscribers: libcxx-commits, christof, krytarowski, srhines.
Herald added a project: libc++.

The workaround added in https://reviews.llvm.org/rL299575 appears to be
working around a bug in Android JB 4.1.x and 4.2.x (API 16 and 17).

Starting in API 16, Android added support for PIE binaries, but the
dynamic linker failed to initialize dlpi_addr to the address that the
executable was loaded at. The bug was fixed in Android JB 4.3.x (API 18).

Improve the true load bias calculation:

- The code was assuming that the first segment would be the PT_PHDR segment. I think it's better to be explicit and search for PT_PHDR. (It will be almost as fast in practice.)
- It's more correct to use p_vaddr rather than p_offset. If a PIE executable is linked with a non-zero image base (e.g. lld's -Wl,--image-base=xxxx), then we must use p_vaddr here.

The "phdr->p_vaddr < image_base" condition seems unnecessary and maybe
slightly wrong. If the OS were to load a binary at an address smaller than
a vaddr in the binary, we would still want to do this workaround.

The workaround is safe when the linker bug isn't present, because it
should calculate an image_base equal to dlpi_addr. Note that with API 21
and up, this workaround should never activate for dynamically-linked
objects, because non-PIE executables aren't allowed.

Consolidate the fix into a single block of code that calculates the true
image base, and make it clear that the fix no longer applies after API 18.

See https://github.com/android/ndk/issues/505 for details.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D68971

Files:
  libunwind/src/AddressSpace.hpp


Index: libunwind/src/AddressSpace.hpp
===================================================================
--- libunwind/src/AddressSpace.hpp
+++ libunwind/src/AddressSpace.hpp
@@ -505,32 +505,40 @@
 #if !defined(Elf_Phdr)
         typedef ElfW(Phdr) Elf_Phdr;
 #endif
+#if !defined(Elf_Addr)
+        typedef ElfW(Addr) Elf_Addr;
+#endif
+
+        Elf_Addr image_base = pinfo->dlpi_addr;
+
+#if defined(__ANDROID__) && __ANDROID_API__ < 18
+        if (image_base == 0) {
+          // Normally, an image base of 0 indicates a non-PIE executable. On
+          // versions of Android prior to API 18, the dynamic linker reported a
+          // dlpi_addr of 0 for PIE executables. Compute the true image base
+          // using the PT_PHDR segment.
+          // See https://github.com/android/ndk/issues/505.
+          for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
+            const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
+            if (phdr->p_type == PT_PHDR) {
+              image_base = reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
+                  phdr->p_vaddr;
+              break;
+            }
+          }
+        }
+#endif
 
  #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
   #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
    #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
   #endif
         size_t object_length;
-#if defined(__ANDROID__)
-#if !defined(Elf_Addr)
-        typedef ElfW(Addr) Elf_Addr;
-#endif
-        Elf_Addr image_base =
-            pinfo->dlpi_phnum
-                ? reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
-                      reinterpret_cast<const Elf_Phdr *>(pinfo->dlpi_phdr)
-                          ->p_offset
-                : 0;
-#endif
 
         for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
           const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
           if (phdr->p_type == PT_LOAD) {
-            uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
-#if defined(__ANDROID__)
-            if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
-              begin = begin + image_base;
-#endif
+            uintptr_t begin = image_base + phdr->p_vaddr;
             uintptr_t end = begin + phdr->p_memsz;
             if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
               cbdata->sects->dso_base = begin;
@@ -539,11 +547,7 @@
             }
           } else if (phdr->p_type == PT_GNU_EH_FRAME) {
             EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
-            uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr;
-#if defined(__ANDROID__)
-            if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
-              eh_frame_hdr_start = eh_frame_hdr_start + image_base;
-#endif
+            uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
             cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
             cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
             found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
@@ -564,12 +568,12 @@
         for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
           const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
           if (phdr->p_type == PT_LOAD) {
-            uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
+            uintptr_t begin = image_base + phdr->p_vaddr;
             uintptr_t end = begin + phdr->p_memsz;
             if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
               found_obj = true;
           } else if (phdr->p_type == PT_ARM_EXIDX) {
-            uintptr_t exidx_start = pinfo->dlpi_addr + phdr->p_vaddr;
+            uintptr_t exidx_start = image_base + phdr->p_vaddr;
             cbdata->sects->arm_section = exidx_start;
             cbdata->sects->arm_section_length = phdr->p_memsz;
             found_hdr = true;


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D68971.224960.patch
Type: text/x-patch
Size: 3874 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20191015/1ee7b562/attachment.bin>


More information about the libcxx-commits mailing list