Re: Wine and mmap

From: Brian Fundakowski Feldman <green_at_freebsd.org>
Date: Sat, 11 Sep 2004 14:00:00 -0400
On Mon, Sep 06, 2004 at 01:49:35AM -0400, Anish Mistry wrote:
> On Sunday 05 September 2004 05:15 pm, Gerald Pfeifer wrote:
> > [ John, sorry for the duplicate message; this is the correct one. ]
> >
> > On Fri, 27 Aug 2004, John Birrell wrote:
> > > Anish Mistry <mistry.7_at_osu.edu> has developed a patch to choose an
> > > appropriate mmap address. He posted it to -current. I haven't had time to
> > > test it.
> >
> > Thanks for the note.  Will you have time to test/commit this before 5.3?
> >
> > Anish, do you have any news on this patch?  (Wine has been broken for a
> > couple of months now, and it would be great to have at least 5.3 fixed.)
> >
> Well I guess this is my lucky day.  Apply the attached patch for vm_mmap to 
> your kernel and patch the August wine sources with the wine-mmap.patch and 
> compile and install wine (be sure to use gmake).  This is working on my dev 
> system with 6-CURRENT as of Saturday night.
> The wine mmap patch just doesn't reserve the DOS area so DOS programs may not 
> work.  This seems to just work around a side effect of the kernel mmap patch.
> I still think that the kernel mmap patch has issues so I'm hoping Alan can 
> give us some feedback.
> Anyway this worked for me, YMMV.

Do these combined work for you, minus any modifications to mmap(2)?  I do
not feel that the kernel mmap(2) should be modified in this manner, that it
is a strictly userland problem.

Index: lib/libpthread/thread/thr_stack.c
===================================================================
RCS file: /usr/ncvs/src/lib/libpthread/thread/thr_stack.c,v
retrieving revision 1.8
diff -u -r1.8 thr_stack.c
--- lib/libpthread/thread/thr_stack.c	14 Sep 2003 22:39:44 -0000	1.8
+++ lib/libpthread/thread/thr_stack.c	11 Sep 2004 17:17:32 -0000
_at__at_ -61,7 +61,7 _at__at_
  * Base address of the last stack allocated (including its red zone, if
  * there is one).  Stacks are allocated contiguously, starting beyond the
  * top of the main stack.  When a new stack is created, a red zone is
- * typically created (actually, the red zone is simply left unmapped) above
+ * typically created (actually, the red zone is mapped with PROT_NONE) above
  * the top of the stack, such that the stack will not be able to grow all
  * the way to the bottom of the next stack.  This isn't fool-proof.  It is
  * possible for a stack to grow by a large amount, such that it grows into
_at__at_ -134,6 +134,7 _at__at_
 	kse_critical_t crit;
 	size_t stacksize;
 	size_t guardsize;
+	char *stackaddr;
 
 	/*
 	 * Round up stack size to nearest multiple of _thr_page_size so
_at__at_ -194,7 +195,7 _at__at_
 			    _thr_guard_default;
 
 		/* Allocate a new stack. */
-		attr->stackaddr_attr = last_stack - stacksize;
+		stackaddr = last_stack - stacksize - guardsize;
 
 		/*
 		 * Even if stack allocation fails, we don't want to try to
_at__at_ -209,11 +210,20 _at__at_
 		KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
 		_kse_critical_leave(crit);
 
-		/* Map the stack, but not the guard page: */
-		if ((attr->stackaddr_attr = mmap(attr->stackaddr_attr,
-		     stacksize, PROT_READ | PROT_WRITE, MAP_STACK,
-		     -1, 0)) == MAP_FAILED)
-			attr->stackaddr_attr = NULL;
+		/* Map the stack and guard page together, and split guard
+		   page from allocated space: */
+		if ((stackaddr = mmap(stackaddr, stacksize+guardsize,
+		     PROT_READ | PROT_WRITE, MAP_STACK,
+		     -1, 0)) != MAP_FAILED &&
+		    (guardsize == 0 ||
+		     mprotect(stackaddr, guardsize, PROT_NONE) == 0)) {
+			stackaddr += guardsize;
+		} else {
+			if (stackaddr != MAP_FAILED)
+				munmap(stackaddr, stacksize + guardsize);
+			stackaddr = NULL;
+		}
+		attr->stackaddr_attr = stackaddr;
 	}
 	if (attr->stackaddr_attr != NULL)
 		return (0);
Index: libexec/rtld-elf/map_object.c
===================================================================
RCS file: /usr/ncvs/src/libexec/rtld-elf/map_object.c,v
retrieving revision 1.15
diff -u -r1.15 map_object.c
--- libexec/rtld-elf/map_object.c	3 Aug 2004 08:50:58 -0000	1.15
+++ libexec/rtld-elf/map_object.c	11 Sep 2004 17:41:28 -0000
_at__at_ -46,12 +46,15 _at__at_
  * Map a shared object into memory.  The "fd" argument is a file descriptor,
  * which must be open on the object and positioned at its beginning.
  * The "path" argument is a pathname that is used only for error messages.
+ * The "low_addr" argument allows for addresses below the normal data
+ * area start to be used for mapping if no space is available above.
  *
  * The return value is a pointer to a newly-allocated Obj_Entry structure
  * for the shared object.  Returns NULL on failure.
  */
 Obj_Entry *
-map_object(int fd, const char *path, const struct stat *sb)
+map_object(int fd, const char *path, const struct stat *sb,
+    unsigned long low_addr)
 {
     Obj_Entry *obj;
     Elf_Ehdr *hdr;
_at__at_ -152,6 +155,15 _at__at_
 
     mapbase = mmap(base_addr, mapsize, convert_prot(segs[0]->p_flags),
       convert_flags(segs[0]->p_flags), fd, base_offset);
+    /*
+     * If requested and out of space for the library, try again below
+     * the normal minimum data segment address.
+     */
+    if (mapbase == (caddr_t) -1 && base_addr == NULL && low_addr != 0) {
+	base_addr = (caddr_t) low_addr;
+	mapbase = mmap(base_addr, mapsize, convert_prot(segs[0]->p_flags),
+          convert_flags(segs[0]->p_flags), fd, base_offset);
+    }
     if (mapbase == (caddr_t) -1) {
 	_rtld_error("%s: mmap of entire address space failed: %s",
 	  path, strerror(errno));
Index: libexec/rtld-elf/rtld.c
===================================================================
RCS file: /usr/ncvs/src/libexec/rtld-elf/rtld.c,v
retrieving revision 1.99
diff -u -r1.99 rtld.c
--- libexec/rtld-elf/rtld.c	4 Aug 2004 19:12:14 -0000	1.99
+++ libexec/rtld-elf/rtld.c	11 Sep 2004 17:51:00 -0000
_at__at_ -143,6 +143,9 _at__at_
 static char *ld_library_path;	/* Environment variable for search path */
 static char *ld_preload;	/* Environment variable for libraries to
 				   load first */
+static unsigned long ld_library_low_addr;	/* Environment variable for
+						   alternate data area to
+						   try to map into */
 static char *ld_tracing;	/* Called from ldd to print libs */
 static Obj_Entry *obj_list;	/* Head of linked list of shared objects */
 static Obj_Entry **obj_tail;	/* Link field of last object in list */
_at__at_ -287,6 +290,14 _at__at_
 
     ld_bind_now = getenv(LD_ "BIND_NOW");
     if (trust) {
+	const char *env_low_addr = getenv(LD_ "LIBRARY_LOW_ADDR");
+	if (env_low_addr != NULL) {
+	    char *low_addr_endptr = NULL;
+	    errno = 0;
+	    ld_library_low_addr = strtoul(env_low_addr, &low_addr_endptr, 0);
+	    if (*low_addr_endptr != '\0' || errno != 0)
+		ld_library_low_addr = 0;
+	}
 	ld_debug = getenv(LD_ "DEBUG");
 	libmap_disable = getenv(LD_ "LIBMAP_DISABLE") != NULL;
 	ld_library_path = getenv(LD_ "LIBRARY_PATH");
_at__at_ -308,7 +319,7 _at__at_
     if (aux_info[AT_EXECFD] != NULL) {	/* Load the main program. */
 	int fd = aux_info[AT_EXECFD]->a_un.a_val;
 	dbg("loading main program");
-	obj_main = map_object(fd, argv0, NULL);
+	obj_main = map_object(fd, argv0, NULL, 0);
 	close(fd);
 	if (obj_main == NULL)
 	    die();
_at__at_ -1249,7 +1260,7 _at__at_
 
     if (obj == NULL) {	/* First use of this object, so we must map it in */
 	dbg("loading \"%s\"", path);
-	obj = map_object(fd, path, &sb);
+	obj = map_object(fd, path, &sb, ld_library_low_addr);
 	close(fd);
 	if (obj == NULL) {
 	    free(path);
Index: libexec/rtld-elf/rtld.h
===================================================================
RCS file: /usr/ncvs/src/libexec/rtld-elf/rtld.h,v
retrieving revision 1.34
diff -u -r1.34 rtld.h
--- libexec/rtld-elf/rtld.h	3 Aug 2004 08:50:58 -0000	1.34
+++ libexec/rtld-elf/rtld.h	11 Sep 2004 17:41:45 -0000
_at__at_ -209,7 +209,8 _at__at_
 } SymCache;
 
 extern void _rtld_error(const char *, ...) __printflike(1, 2);
-extern Obj_Entry *map_object(int, const char *, const struct stat *);
+extern Obj_Entry *map_object(int, const char *, const struct stat *,
+				unsigned long);
 extern void *xcalloc(size_t);
 extern void *xmalloc(size_t);
 extern char *xstrdup(const char *);

-- 
Brian Fundakowski Feldman                           \'[ FreeBSD ]''''''''''\
  <> green_at_FreeBSD.org                               \  The Power to Serve! \
 Opinions expressed are my own.                       \,,,,,,,,,,,,,,,,,,,,,,\
Received on Sat Sep 11 2004 - 16:00:16 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:11 UTC