Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 17 Feb 2013 20:57:24 GMT
From:      Damjan Jovanovic <damjan.jov@gmail.com>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/176216: [patch] Allow loading ELF libraries at their preferred base address (needed for Wine)
Message-ID:  <201302172057.r1HKvOnQ060555@red.freebsd.org>
Resent-Message-ID: <201302172100.r1HL00GN090039@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>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:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201302172057.r1HKvOnQ060555>