libgcc: work around old Bionic loader bug

dl_iterate_phdr returns a 0 load_base for a PIE executable when it should
return the address where the executable was loaded (e.g. the load base or
load bias). Recalculate the load base when it is zero. This recalculation
should work on any ELF file with a PT_PHDR segment -- it will calculate 0
for a non-PIE executable.

The load base is added to an ELF virtual address to produce a run-time
address. Recalculate it by subtracting the PT_PHDR's virtual address from
its run-time address.

Bug: https://github.com/android-ndk/ndk/issues/505
Test: manual
Test: run NDK tests (./checkbuild.py && ./run_tests.py)
Change-Id: I7de46c07a8b04e794b59f07b4d554238cfd6d5d9
diff --git a/gcc-4.9/libgcc/unwind-dw2-fde-dip.c b/gcc-4.9/libgcc/unwind-dw2-fde-dip.c
index d6c0521..db98b59 100644
--- a/gcc-4.9/libgcc/unwind-dw2-fde-dip.c
+++ b/gcc-4.9/libgcc/unwind-dw2-fde-dip.c
@@ -183,6 +183,30 @@
   p_eh_frame_hdr = NULL;
   p_dynamic = NULL;
 
+#if defined(__BIONIC__) && defined(__i386__)
+  if (load_base == 0)
+    {
+      /* A load_base of 0 normally indicates a non-PIE executable. There was a
+	 bug in Android's dynamic loader prior to API 18, though, where
+	 dl_iterate_phdr incorrectly passed a load_base of 0 for a PIE
+	 executable. Work around the bug by recalculating load_base using
+	 the PT_PHDR segment. This code path isn't needed for arm32, because
+	 arm32 didn't have dl_iterate_phdr until API 21.
+	 https://github.com/android-ndk/ndk/issues/505. */
+      size_t i;
+      for (i = 0; i < info->dlpi_phnum; ++i)
+	{
+	  const ElfW(Phdr) *fix_phdr = &info->dlpi_phdr[i];
+	  if (fix_phdr->p_type == PT_PHDR)
+	    {
+	      load_base = (_Unwind_Ptr) info->dlpi_phdr -
+			  (_Unwind_Ptr) fix_phdr->p_vaddr;
+	      break;
+	    }
+	}
+    }
+#endif
+
   struct frame_hdr_cache_element *prev_cache_entry = NULL,
     *last_cache_entry = NULL;