Alexandre Julliard julliard@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 wrote:
Alexandre Julliard julliard@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?
This seems to work fine here (Red Hat 7):
james[38]%uname -a Linux 24-28-218-19 2.4.5-pre3 #12 Fri May 18 23:56:59 EDT 2001 i586 unknown james[40]%rpm -q glibc glibc-2.2-12 james[41]%rpm -q gcc gcc-2.96-85
-- James Juran jamesjuran@alumni.psu.edu
On Wednesday 13 June 2001 07:31 pm, you wrote:
Alexandre Julliard julliard@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?
With kernel 2.4.5-ac9, RedHat 6.1, it works fine with any crashing of the official AIM client, though I didn't test it that hard...
On 13 Jun 2001, Alexandre Julliard wrote:
OK, here we go. Could you please test this, especially people running kernel 2.4?
Index: memory/virtual.c
Looks good to me. First problem app runs OK, and you get this by the second one.
gcc version 2.95.3 20010315 (release) /lib/libc.so.6 -> libc-2.1.3.so* Linux giftie 2.4.5 #1 Sat Jun 2 11:23:22 EDT 2001 i586 unknown
Lawson ---cut here---
________________________________________________________________ GET INTERNET ACCESS FROM JUNO! Juno offers FREE or PREMIUM Internet access for less! Join Juno today! For your FREE software, visit: http://dl.www.juno.com/get/tagj.
On Thu, 14 Jun 2001 lawson_whitney@juno.com wrote:
On 13 Jun 2001, Alexandre Julliard wrote:
OK, here we go. Could you please test this, especially people running kernel 2.4?
Index: memory/virtual.c
Looks good to me. First problem app runs OK, and you get this by the second one.
gcc version 2.95.3 20010315 (release) /lib/libc.so.6 -> libc-2.1.3.so* Linux giftie 2.4.5 #1 Sat Jun 2 11:23:22 EDT 2001 i586 unknown
Lawson ---cut here---
Also works fine with: /lib/libc.so.6 -> libc-2.2.3.so* (same kernel and gcc).
Not a surprise, but just to be thorough.
Lawson ---cut---
________________________________________________________________ GET INTERNET ACCESS FROM JUNO! Juno offers FREE or PREMIUM Internet access for less! Join Juno today! For your FREE software, visit: http://dl.www.juno.com/get/tagj.
On Wed, Jun 13, 2001 at 07:31:33PM -0700, Alexandre Julliard wrote:
Alexandre Julliard julliard@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?
Works fine here (glibc 2.2.1, linux 2.4.2-ac).
Ciao, Marcus