From 4089f56e6c7438eb98cb86c249cf0c01e22219c5 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Wed, 27 Jun 2018 17:21:50 -0700 Subject: 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 --- gcc-4.9/libgcc/unwind-dw2-fde-dip.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/gcc-4.9/libgcc/unwind-dw2-fde-dip.c b/gcc-4.9/libgcc/unwind-dw2-fde-dip.c index d6c052165..db98b5961 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 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr) 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; -- cgit v1.2.3