aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/libc/gen/elf_utils.c15
1 files changed, 14 insertions, 1 deletions
diff --git a/lib/libc/gen/elf_utils.c b/lib/libc/gen/elf_utils.c
index 06c91e057487..417f1842aadd 100644
--- a/lib/libc/gen/elf_utils.c
+++ b/lib/libc/gen/elf_utils.c
@@ -47,8 +47,21 @@ __elf_phdr_match_addr(struct dl_phdr_info *phdr_info, void *addr)
for (i = 0; i < phdr_info->dlpi_phnum; i++) {
ph = &phdr_info->dlpi_phdr[i];
- if (ph->p_type != PT_LOAD || (ph->p_flags & PF_X) == 0)
+ if (ph->p_type != PT_LOAD)
continue;
+
+ /* ELFv1 ABI for powerpc64 passes function descriptor
+ * pointers around, not function pointers. The function
+ * descriptors live in .opd, which is a non-executable segment.
+ * The PF_X check would therefore make all address checks fail,
+ * causing a crash in some instances. Don't skip over
+ * non-executable segments in the ELFv1 powerpc64 case.
+ */
+#if !defined(__powerpc64__) || (defined(_CALL_ELF) && _CALL_ELF == 2)
+ if ((ph->p_flags & PF_X) == 0)
+ continue;
+#endif
+
if (phdr_info->dlpi_addr + ph->p_vaddr <= (uintptr_t)addr &&
(uintptr_t)addr + sizeof(addr) < phdr_info->dlpi_addr +
ph->p_vaddr + ph->p_memsz)