virtual memory problems with Linux 2.4.5

Alexandre Julliard julliard at winehq.com
Wed Jun 13 21:31:33 CDT 2001


Alexandre Julliard <julliard at winehq.com> writes:

> Another related problem is that even without this bug, mmap64 will
> always refuse to do an unaligned mmap, even if the kernel might have
> accepted it (with kernel 2.2.x for instance). Maybe the best solution
> would be to directly call the mmap syscall instead of mmap2 when
> mapping executables, this would fix both problems.

OK, here we go. Could you please test this, especially people running
kernel 2.4?

Index: memory/virtual.c
===================================================================
RCS file: /opt/cvs-commit/wine/memory/virtual.c,v
retrieving revision 1.63
diff -u -r1.63 virtual.c
--- memory/virtual.c	2001/06/13 20:13:20	1.63
+++ memory/virtual.c	2001/06/14 02:15:36
@@ -104,7 +104,8 @@
 #define VIRTUAL_DEBUG_DUMP_VIEW(view) \
    if (!TRACE_ON(virtual)); else VIRTUAL_DumpView(view)
 
-static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size, DWORD offset, int prot, int flags );
+static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size, DWORD offset_low,
+                            DWORD offset_high, int prot, int flags );
 
 /* filter for page-fault exceptions */
 static WINE_EXCEPTION_FILTER(page_fault)
@@ -471,7 +472,7 @@
 
     /* map the header */
 
-    if (VIRTUAL_mmap( fd, ptr, header_size, 0, PROT_READ | PROT_WRITE,
+    if (VIRTUAL_mmap( fd, ptr, header_size, 0, 0, PROT_READ | PROT_WRITE,
                       MAP_PRIVATE | MAP_FIXED ) == (char *)-1) goto error;
     dos = (IMAGE_DOS_HEADER *)ptr;
     nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew);
@@ -533,7 +534,7 @@
                           sec->PointerToRawData, pos, sec->SizeOfRawData,
                           size, sec->Characteristics );
             if (VIRTUAL_mmap( shared_fd, (char *)ptr + sec->VirtualAddress, size,
-                              pos, PROT_READ|PROT_WRITE|PROT_EXEC,
+                              pos, 0, PROT_READ|PROT_WRITE|PROT_EXEC,
                               MAP_SHARED|MAP_FIXED ) == (void *)-1)
             {
                 ERR_(module)( "Could not map shared section %.8s\n", sec->Name );
@@ -555,7 +556,7 @@
          *       fall back to read(), so we don't need to check anything here.
          */
         if (VIRTUAL_mmap( fd, (char *)ptr + sec->VirtualAddress, sec->SizeOfRawData,
-                          sec->PointerToRawData, PROT_READ|PROT_WRITE|PROT_EXEC,
+                          sec->PointerToRawData, 0, PROT_READ|PROT_WRITE|PROT_EXEC,
                           MAP_PRIVATE | MAP_FIXED ) == (void *)-1)
         {
             ERR_(module)( "Could not map section %.8s, file probably truncated\n", sec->Name );
@@ -650,6 +651,46 @@
 }
 
 
+
+/***********************************************************************
+ *           unaligned_mmap
+ *
+ * Linux kernels before 2.4.x can support non page-aligned offsets, as
+ * long as the offset is aligned to the filesystem block size. This is
+ * a big performance gain so we want to take advantage of it.
+ *
+ * However, when we use 64-bit file support this doesn't work because
+ * glibc rejects unaligned offsets. Also glibc 2.1.3 mmap64 is broken
+ * in that it rounds unaligned offsets down to a page boundary. For
+ * these reasons we do a direct system call here.
+ */
+static void *unaligned_mmap( void *addr, size_t length, unsigned int prot,
+                             unsigned int flags, int fd, unsigned int offset_low,
+                             unsigned int offset_high )
+{
+#if defined(linux) && defined(__i386__) && defined(__GNUC__)
+    if (!offset_high && (offset_low & page_mask))
+    {
+        int ret;
+        __asm__ __volatile__("push %%ebx\n\t"
+                             "movl %2,%%ebx\n\t"
+                             "int $0x80\n\t"
+                             "popl %%ebx"
+                             : "=a" (ret)
+                             : "0" (90), /* SYS_mmap */
+                               "g" (&addr) );
+        if (ret < 0 && ret > -4096)
+        {
+            errno = -ret;
+            ret = -1;
+        }
+        return (void *)ret;
+    }
+#endif
+    return mmap( addr, length, prot, flags, fd, ((off_t)offset_high << 32) | offset_low );
+}
+
+
 /***********************************************************************
  *           VIRTUAL_mmap
  *
@@ -657,15 +698,16 @@
  * and falls back to read if mmap of a file fails.
  */
 static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size,
-                            DWORD offset, int prot, int flags )
+                            DWORD offset_low, DWORD offset_high, int prot, int flags )
 {
     int pos;
     LPVOID ret;
+    off_t offset;
 
     if (fd == -1) return wine_anon_mmap( start, size, prot, flags );
 
-    if ((ret = mmap( start, size, prot, flags, fd, offset )) != (LPVOID)-1)
-        return ret;
+    if ((ret = unaligned_mmap( start, size, prot, flags, fd,
+                               offset_low, offset_high )) != (LPVOID)-1) return ret;
 
     /* mmap() failed; if this is because the file offset is not    */
     /* page-aligned (EINVAL), or because the underlying filesystem */
@@ -687,6 +729,7 @@
     ret = wine_anon_mmap( start, size, PROT_READ | PROT_WRITE, flags );
     if (ret == (LPVOID)-1) return ret;
     /* Now read in the file */
+    offset = ((off_t)offset_high << 32) | offset_low;
     if ((pos = lseek( fd, offset, SEEK_SET )) == -1)
     {
         munmap( ret, size );
@@ -1524,8 +1567,8 @@
                           shared_file, shared_size );
 
 
-    if (size_high || offset_high)
-        ERR("Offsets larger than 4Gb not supported\n");
+    if (size_high)
+        ERR("Sizes larger than 4Gb not supported\n");
 
     if ((offset_low >= size_low) ||
         (count > size_low - offset_low))
@@ -1570,7 +1613,7 @@
 
     TRACE("handle=%x size=%x offset=%lx\n", handle, size, offset_low );
 
-    ptr = (UINT)VIRTUAL_mmap( unix_handle, addr, size, offset_low,
+    ptr = (UINT)VIRTUAL_mmap( unix_handle, addr, size, offset_low, offset_high,
                               VIRTUAL_GetUnixProt( prot ), flags );
     if (ptr == (UINT)-1) {
         /* KB: Q125713, 25-SEP-1995, "Common File Mapping Problems and


-- 
Alexandre Julliard
julliard at winehq.com




More information about the wine-devel mailing list