Re: Random Solaris 7 x86 issues
(I hope this doesn't get me into trouble with the wine-devel mailing list... My Netscape doesn't seem to understand it.) To whomever is interested, A couple of minutes hacking at my Solaris 8 (Sparc) machine during the lunch break yields the attached code that seems to emulate Linux' behaviour. Do whatever you feel is best. My $0.02, Erik Boasson. -- [Unclassified] #include sys/types.h #include sys/wait.h #include sys/stat.h #include sys/mman.h #include errno.h #include unistd.h #include fcntl.h #include assert.h #include alloca.h #include stdio.h #include string.h #include signal.h #include procfs.h static int is_mapped_test (uintptr_t vaddr, size_t size, const prmap_t *asmap, int n) { int i = 0, j = n; while (i j) { int m = (i + j) / 2; const prmap_t *o = asmap[m]; if ((uintptr_t) o-pr_vaddr = vaddr + size) j = m; else if ((uintptr_t) o-pr_vaddr + o-pr_size = vaddr) i = m + 1; else return 1; } return 0; } static void *safe_mmap (void *addr, size_t len, int prot, int flags, int fildes, off_t off) { if (flags MAP_FIXED) return mmap (addr, len, prot, flags, fildes, off); else { int stat = 0; pid_t pid; int fd; struct stat sb; prmap_t *asmap; void *actual_addr; assert ((fd = open ("/proc/self/rmap", O_RDONLY)) != -1); if ((pid = vfork ()) == -1) { perror ("is_mapped: vfork"); abort (); } else if (pid == 0) { fstat (fd, sb); asmap = alloca (sb.st_size); read (fd, asmap, sb.st_size); if (is_mapped_test ((uintptr_t) addr, len, asmap, sb.st_size / sizeof (prmap_t))) _exit (EADDRINUSE); else if ((actual_addr = mmap (addr, len, prot, flags | MAP_FIXED, fildes, off)) == (void *) -1) _exit (errno); else if (actual_addr != addr) { munmap (actual_addr, len); kill (getpid (), SIGKILL); } else { _exit (0); } } else if (waitpid (pid, stat, WNOHANG) != pid) { perror ("is_mapped: waitpid"); abort (); } close (fd); if (!WIFEXITED (stat)) return mmap (addr, len, prot, flags, fildes, off); else if (WEXITSTATUS (stat) == 0) return addr; else if (WEXITSTATUS (stat) == EADDRINUSE) return mmap (addr, len, prot, flags, fildes, off); else { errno = WEXITSTATUS (stat); return (void *) -1; } } } /*/ #include time.h #include stdio.h #include stdlib.h void try (uintptr_t vaddr, size_t size) { void *a; a = safe_mmap ((void *) vaddr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); printf ("%8x .. %8x %8p %s\n", vaddr, vaddr + size, a, strerror (errno)); if (a != (void *) -1) munmap (a, size); } int main (int argc, char **argv) { char buf[128]; int i; sprintf (buf, "/usr/proc/bin/pmap %d", (int) getpid ()); system (buf); srandom (time (0)); for (i = 1; i argc; i++) { uintptr_t vaddr; size_t size; if (sscanf (argv[i], "%x+%x", vaddr, size) == 2) { try (vaddr, size); } else { int n = atoi (argv[i]); while (n-- 0) { do { vaddr = random () -8192; size = (random () % 1048576) -8192; } while (vaddr + size vaddr); try (vaddr, size); } } } return 0; }
RE: Random Solaris 7 x86 issues
(I hope this doesn't get me into trouble with the wine-devel mailing list... My Netscape doesn't seem to understand it.) My Microsoft Outlook understands it perfectly. To whomever is interested, I am. :-) A couple of minutes hacking at my Solaris 8 (Sparc) machine during the lunch break yields the attached code that seems to emulate Linux' behaviour. Do whatever you feel is best. Intresting. The vfork confused me at first but I guess it is for suspending the other threads in the process. The Solaris 2.6 man page says that it suspends the parent process and meantions that for multithreaded process only the thread of control is borrowed. It doesn't explictly says that all other threads in the parent process are suspended but I guess they are. Since Wine on Solaris maps Win32 processes to Solaris processes and Win32 threads to Solaris threads (or rather LWP:s) it might just fix the race Alexandre and/or Ulrich was talking about. However I can't test your application with Solaris 2.6 (Intel) since it lacks MAP_ANON. I think that it is possible to do that with a temporary dummy file instead and I think there is code somethere in Wine that actually does this.
RE: Random Solaris 7 x86 issues
Here are various things I'm seeing. 1) Running anything produces: err:dosmem:setup_dos_mem Cannot use first megabyte for DOS address space, please report 2) Solitaire seems to work fine. 3) Running telnet produces: err:win32:do_relocations FATAL: Need to relocate C:Ă–WINDOWSĂ–TELNET.EXE, but no relocation records present (stripped during link). Try to run that file directly The following patch to map_image allows telnet to start up: [snip] OK. mmap on Solaris has slightly different semantics than mmap on Linux if an address is specified and/or MAP_FIXED is specified. The other cases are the same however. I don't remember exactly what the difference is but IIRC on Linux if an address is specified and the address is page aligned it maps on that adress regardless whether MAP_FIXED is specified. Solaris on the other hand uses the address only as a hint regardless of whether it is page aligned or not unless of course MAP_FIXED is specified. So this means that your patch might indead be the correct fix. Ulrich know more about this than I do. Ulrich? PS. BTW does an addition of MAP_FIXED in setup_dos_mem help?
Re: Random Solaris 7 x86 issues
Patrik Stridvall wrote: OK. mmap on Solaris has slightly different semantics than mmap on Linux if an address is specified and/or MAP_FIXED is specified. The other cases are the same however. I don't remember exactly what the difference is but IIRC on Linux if an address is specified and the address is page aligned it maps on that adress regardless whether MAP_FIXED is specified. Solaris on the other hand uses the address only as a hint regardless of whether it is page aligned or not unless of course MAP_FIXED is specified. So this means that your patch might indead be the correct fix. Ulrich know more about this than I do. Ulrich? The problem is the following: if you pass MAP_FIXED to mmap(), it *will* use this address no matter what. Especially, if there are already *other* mappings in that range, they will just be zapped. This is same for both Linux and Solaris. On the other hand, if you do *not* pass MAP_FIXED, the address passed to mmap() is only a *hint* of where to place the mapping. Both Linux and Solaris are free to chose some other address. In no case will old mappings be affected. Again, the semantics is the same for both Linux and Solaris. However, the *implementation* is quite different: Linux will always try to place the mapping at exactly the address specified, and will only chose a different address if the other is already taken. Solaris, however, will nearly always move the mapping to some other address, apparently due to efficiency considerations. This creates a problem for Wine, because be sometimes *have* to place a mapping at a particular address, e.g. non-relocateable executable images. What we need here is a routine that tries to place the mapping at exactly the specified address, but if this is not possible, does *not* zap any other mappings but returns an error. On top of the Linux mmap(), this is easily done: just call mmap() with the address, and without MAP_FIXED, and check the return value: if the system chose another address, we know that we have failed. On top of the Solaris mmap(), we have a problem: we can't use MAP_FIXED as this might zap other mappings, and we can't *not* use MAP_FIXED, because then the system nearly never choses the address we need, even though it were possible. One possible solution would be to perform ourselves a check whether the target region is free from other mappings, and if so, use mmap() with MAP_FIXED. One way to do this would be to scan the proc file system entry for the current process to find out the current mappings. (Another way would be to check our own reprentation of the address space as list of FILE_VIEW data structures. We need to take care that we don't overlook system mappings in this case ...) There is also a not quite trivial problem of how to avoid race conditions here ... Bye, Ulrich -- Dr. Ulrich Weigand [EMAIL PROTECTED]
Re: Random Solaris 7 x86 issues
Alexandre Julliard wrote: Does anybody know exactly what Solaris does? Does it simply round the address to some nearest boundary, or does it pick a completely random address? If it's just rounding we could allocate a larger area and use the part that we wanted, but if the address is random this won't work. Well, a little test program shows (on Solaris 2.5.1): 1234 -- ef6f -- ef6c 1000 -- ef6b -- ef6a and on Solaris 2.6: 1234 -- ef6f -- ef6d 1000 -- ef6c -- ef6b and on Solaris 2.7: 1234 -- ff39 -- ff37 1000 -- ff36 -- ff35 all on Sparc; always 16K allocations. So it would appear that Solaris completely ignores the passed address, and just sorts all mmaps() nicely together ;-) And no, MAP_FIXED does not work since it will wipe out existing mappings at this address. Yes. Except if we check ourselves in advance ... Bye, Ulrich -- Dr. Ulrich Weigand [EMAIL PROTECTED]
Re: Random Solaris 7 x86 issues
Patrik Stridvall [EMAIL PROTECTED] writes: Solaris on the other hand uses the address only as a hint regardless of whether it is page aligned or not unless of course MAP_FIXED is specified. Does anybody know exactly what Solaris does? Does it simply round the address to some nearest boundary, or does it pick a completely random address? If it's just rounding we could allocate a larger area and use the part that we wanted, but if the address is random this won't work. And no, MAP_FIXED does not work since it will wipe out existing mappings at this address. -- Alexandre Julliard [EMAIL PROTECTED]
Re: Random Solaris 7 x86 issues
The problem is the following: if you pass MAP_FIXED to mmap(), it *will* use this address no matter what. Especially, if there are already *other* mappings in that range, they will just be zapped. Yes. :-( One possible solution would be to perform ourselves a check whether the target region is free from other mappings, and if so, use mmap() with MAP_FIXED. One way to do this would be to scan the proc file system entry for the current process to find out the current mappings. (Another way would be to check our own reprentation of the address space as list of FILE_VIEW data structures. We need to take care that we don't overlook system mappings in this case ...) There is also a not quite trivial problem of how to avoid race conditions here ... I started to code this last night using mincore to check each page in the target region one at a time (which should be somewhat portable), however I didn't see an easy / obvious way to ensure that all other threads are quiescent. -- John - | Feith Systems | Voice: 1-215-646-8000 | Email: [EMAIL PROTECTED] | |John Wehle| Fax: 1-215-540-5495 | | -
Re: Random Solaris 7 x86 issues
Ulrich Weigand [EMAIL PROTECTED] writes: So it would appear that Solaris completely ignores the passed address, and just sorts all mmaps() nicely together ;-) Great :-( And what does the address space look like at startup? Where does it allocate the main exe and the .so libraries? Maybe we can reserve the addresses we need like 0 and 0x0040 with a MAP_FIXED at startup. And no, MAP_FIXED does not work since it will wipe out existing mappings at this address. Yes. Except if we check ourselves in advance ... You'd need to completely freeze all threads first, because you never know if some libc function is not going to change mappings. -- Alexandre Julliard [EMAIL PROTECTED]
Re: Random Solaris 7 x86 issues
John Wehle wrote: I started to code this last night using mincore to check each page in the target region one at a time (which should be somewhat portable), I don't think mincore is appropriate, as we must check whether there *is* a mapping, not just whether some of its pages are actually present in physical memory. Even if a mapping happens to be completely paged out we still must not zap it. Scanning the list of mappings from the proc file system should work, though. however I didn't see an easy / obvious way to ensure that all other threads are quiescent. This is indeed the main problem here ... Bye, Ulrich -- Dr. Ulrich Weigand [EMAIL PROTECTED]
Re: Random Solaris 7 x86 issues
I don't think mincore is appropriate, as we must check whether there *is* a mapping, not just whether some of its pages are actually present in physical memory. Sure it is. The question is did mincore return an *error* for the page being checked (in which case nothing is mapped there) or did it return zero (in which case something is mapped there). Ah, sorry. You're right, of course. Using mincore should be somewhat more portable than digging around /proc. Yes. The /proc format changed even across Solaris versions :-/ Bye, Ulrich -- Dr. Ulrich Weigand [EMAIL PROTECTED]
Re: Random Solaris 7 x86 issues
Alexandre Julliard wrote: Great :-( And what does the address space look like at startup? Where does it allocate the main exe and the .so libraries? Maybe we can reserve the addresses we need like 0 and 0x0040 with a MAP_FIXED at startup. Well, my little test app looks like this: 7499: ./test 0001 8K read/exec /home/inf1/weigand/test 0002 8K read/write/exec /home/inf1/weigand/test FF28656K read/exec /usr/lib/libc.so.1 FF332000 32K read/write/exec /usr/lib/libc.so.1 FF33A000 8K read/write/exec [ anon ] FF35 16K write [ anon ] FF36 16K write [ anon ] FF37 16K write [ anon ] FF38 16K read/exec /usr/platform/sun4u/lib/libc_psr.so.1 FF39 16K write [ anon ] FF3A 8K read/exec /usr/lib/libdl.so.1 FF3B128K read/exec /usr/lib/ld.so.1 FF3DE000 16K read/write/exec /usr/lib/ld.so.1 FFBEC000 16K read/write/exec [ stack ] total 960K So at least the libraries are no problem. The executable base address is not so nice, but there we could probably fiddle around with linker scripts ... Note that this is on Sparc, as I don't have access to a Solaris/x86 box. John, does it look much different there? And no, MAP_FIXED does not work since it will wipe out existing mappings at this address. Yes. Except if we check ourselves in advance ... You'd need to completely freeze all threads first, because you never know if some libc function is not going to change mappings. Yes, that's the problem. :-/ Bye, Ulrich -- Dr. Ulrich Weigand [EMAIL PROTECTED]
Re: Random Solaris 7 x86 issues
Note that this is on Sparc, as I don't have access to a Solaris/x86 box. John, does it look much different there? 14420: ./a 08046000 8K read/write/exec [ stack ] 0805 4K read/exec /tmp/a 0806 4K read/write/exec /tmp/a DFB3F000552K read/exec /usr/lib/libc.so.1 DFBC9000 28K read/write/exec /usr/lib/libc.so.1 DFBD 4K read/write/exec [ anon ] DFBD2000108K read/exec /usr/lib/ld.so.1 DFBF8000 4K read/exec /usr/lib/libdl.so.1 DFBFA000 4K read/write/exec [ anon ] DFBFC000 12K read/write/exec /usr/lib/ld.so.1 total 728K This is on Solaris 7 x86. -- John - | Feith Systems | Voice: 1-215-646-8000 | Email: [EMAIL PROTECTED] | |John Wehle| Fax: 1-215-540-5495 | | -