>Number:         176216
>Category:       kern
>Synopsis:       [patch] Allow loading ELF libraries at their preferred base 
>address (needed for Wine)
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun Feb 17 21:00:00 UTC 2013
>Closed-Date:
>Last-Modified:
>Originator:     Damjan Jovanovic
>Release:        9.1
>Organization:
>Environment:
Any
>Description:
FreeBSD's dynamic linker (/libexec/ld-elf.so.1) currently loads libraries by 
calling mmap() with 0 as the first parameter, causing them to be loaded at 
whatever address the kernel chooses.
But for maximum compatibility with Windows applications, Wine needs some of its 
DLLs to be loaded at particular memory addresses (see the comments on 
https://wiki.freebsd.org/Wine).

With this patch, first mmap() is called with the base address of the library 
and MAP_FIXED, giving the library a chance to load at the base address it 
specified, and if this fails then mmap() is called without MAP_FIXED so the 
library can at least load somewhere else since its preferred memory region is 
unavailable.

>How-To-Repeat:

>Fix:


Patch attached with submission follows:

Index: libexec/rtld-elf/map_object.c
===================================================================
--- libexec/rtld-elf/map_object.c       (revision 246877)
+++ libexec/rtld-elf/map_object.c       (working copy)
@@ -175,11 +175,22 @@
     base_vaddr = trunc_page(segs[0]->p_vaddr);
     base_vlimit = round_page(segs[nsegs]->p_vaddr + segs[nsegs]->p_memsz);
     mapsize = base_vlimit - base_vaddr;
-    base_addr = hdr->e_type == ET_EXEC ? (caddr_t) base_vaddr : NULL;
+    base_addr = (caddr_t) base_vaddr;
 
-    mapbase = mmap(base_addr, mapsize, PROT_NONE, MAP_ANON | MAP_PRIVATE |
-      MAP_NOCORE, -1, 0);
+    /*
+     * Executables, and libraries whose base_addr isn't 0,
+     * should ideally be loaded at that base_addr.
+     */
+    mapbase = (caddr_t) -1;
+    if (base_addr != 0) {
+        mapbase = mmap(base_addr, mapsize, PROT_NONE, MAP_ANON | MAP_PRIVATE |
+          MAP_NOCORE | MAP_FIXED, -1, 0);
+    }
     if (mapbase == (caddr_t) -1) {
+        mapbase = mmap(base_addr, mapsize, PROT_NONE, MAP_ANON | MAP_PRIVATE |
+          MAP_NOCORE, -1, 0);
+    }
+    if (mapbase == (caddr_t) -1) {
        _rtld_error("%s: mmap of entire address space failed: %s",
          path, rtld_strerror(errno));
        goto error;


>Release-Note:
>Audit-Trail:
>Unformatted:
_______________________________________________
freebsd-bugs@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "freebsd-bugs-unsubscr...@freebsd.org"

Reply via email to