about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--arch/sh/reloc.h2
-rw-r--r--src/internal/dynlink.h4
-rw-r--r--src/ldso/dynlink.c19
3 files changed, 21 insertions, 4 deletions
diff --git a/arch/sh/reloc.h b/arch/sh/reloc.h
index d4fe348c..0238ce07 100644
--- a/arch/sh/reloc.h
+++ b/arch/sh/reloc.h
@@ -32,6 +32,8 @@
 #define REL_DTPOFF      R_SH_TLS_DTPOFF32
 #define REL_TPOFF       R_SH_TLS_TPOFF32
 
+#define DL_NOMMU_SUPPORT 1
+
 #if __SH_FDPIC__
 #define REL_FUNCDESC    R_SH_FUNCDESC
 #define REL_FUNCDESC_VAL R_SH_FUNCDESC_VALUE
diff --git a/src/internal/dynlink.h b/src/internal/dynlink.h
index 86f379e6..9c494e43 100644
--- a/src/internal/dynlink.h
+++ b/src/internal/dynlink.h
@@ -64,6 +64,10 @@ struct fdpic_dummy_loadmap {
 #define DL_FDPIC 0
 #endif
 
+#ifndef DL_NOMMU_SUPPORT
+#define DL_NOMMU_SUPPORT 0
+#endif
+
 #if !DL_FDPIC
 #define IS_RELATIVE(x,s) ( \
 	(R_TYPE(x) == REL_RELATIVE) || \
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
index a6484dd5..5fbe2bb5 100644
--- a/src/ldso/dynlink.c
+++ b/src/ldso/dynlink.c
@@ -482,8 +482,14 @@ static void reclaim_gaps(struct dso *dso)
 
 static void *mmap_fixed(void *p, size_t n, int prot, int flags, int fd, off_t off)
 {
-	char *q = mmap(p, n, prot, flags, fd, off);
-	if (q != MAP_FAILED || errno != EINVAL) return q;
+	static int no_map_fixed;
+	char *q;
+	if (!no_map_fixed) {
+		q = mmap(p, n, prot, flags|MAP_FIXED, fd, off);
+		if (!DL_NOMMU_SUPPORT || q != MAP_FAILED || errno != EINVAL)
+			return q;
+		no_map_fixed = 1;
+	}
 	/* Fallbacks for MAP_FIXED failure on NOMMU kernels. */
 	if (flags & MAP_ANONYMOUS) {
 		memset(p, 0, n);
@@ -631,7 +637,11 @@ static void *map_library(int fd, struct dso *dso)
 	 * the length of the file. This is okay because we will not
 	 * use the invalid part; we just need to reserve the right
 	 * amount of virtual address space to map over later. */
-	map = mmap((void *)addr_min, map_len, prot, MAP_PRIVATE, fd, off_start);
+	map = DL_NOMMU_SUPPORT
+		? mmap((void *)addr_min, map_len, PROT_READ|PROT_WRITE|PROT_EXEC,
+			MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
+		: mmap((void *)addr_min, map_len, prot,
+			MAP_PRIVATE, fd, off_start);
 	if (map==MAP_FAILED) goto error;
 	dso->map = map;
 	dso->map_len = map_len;
@@ -656,7 +666,8 @@ static void *map_library(int fd, struct dso *dso)
 			dso->phentsize = eh->e_phentsize;
 		}
 		/* Reuse the existing mapping for the lowest-address LOAD */
-		if ((ph->p_vaddr & -PAGE_SIZE) == addr_min) continue;
+		if ((ph->p_vaddr & -PAGE_SIZE) == addr_min && !DL_NOMMU_SUPPORT)
+			continue;
 		this_min = ph->p_vaddr & -PAGE_SIZE;
 		this_max = ph->p_vaddr+ph->p_memsz+PAGE_SIZE-1 & -PAGE_SIZE;
 		off_start = ph->p_offset & -PAGE_SIZE;