Changed LoadLibraryEx32W16 to use OpenFile16 to look for the file
[wine.git] / libs / wine / port.c
blob35595c54a3393e381174ccdbf5bbfd541a2b7f5e
1 /*
2 * Wine portability routines
4 * Copyright 2000 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <ctype.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_MMAN_H
31 #include <sys/mman.h>
32 #endif
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #ifdef HAVE_STDINT_H
37 # include <stdint.h>
38 #endif
40 #include "wine/library.h"
41 #include "wine/pthread.h"
43 /* Note: the wine_pthread functions are just placeholders,
44 * they will be overridden by the pthread support code.
47 /***********************************************************************
48 * wine_pthread_init_process
50 void wine_pthread_init_process( const struct wine_pthread_functions *functions )
54 /***********************************************************************
55 * wine_pthread_init_thread
57 void wine_pthread_init_thread( struct wine_pthread_thread_info *info )
61 /***********************************************************************
62 * wine_pthread_create_thread
64 int wine_pthread_create_thread( struct wine_pthread_thread_info *info )
66 return -1;
69 /***********************************************************************
70 * wine_pthread_init_current_teb
72 void wine_pthread_init_current_teb( struct wine_pthread_thread_info *info )
76 /***********************************************************************
77 * wine_pthread_get_current_teb
79 void *wine_pthread_get_current_teb(void)
81 return NULL;
84 /***********************************************************************
85 * wine_pthread_exit_thread
87 void wine_pthread_exit_thread( struct wine_pthread_thread_info *info )
89 exit( info->exit_status );
92 /***********************************************************************
93 * wine_pthread_abort_thread
95 void wine_pthread_abort_thread( int status )
97 exit( status );
101 /***********************************************************************
102 * wine_switch_to_stack
104 * Switch to the specified stack and call the function.
106 void DECLSPEC_NORETURN wine_switch_to_stack( void (*func)(void *), void *arg, void *stack );
107 #if defined(__i386__) && defined(__GNUC__)
108 __ASM_GLOBAL_FUNC( wine_switch_to_stack,
109 "movl 4(%esp),%ecx\n\t" /* func */
110 "movl 8(%esp),%edx\n\t" /* arg */
111 "movl 12(%esp),%esp\n\t" /* stack */
112 "pushl %edx\n\t"
113 "xorl %ebp,%ebp\n\t"
114 "call *%ecx\n\t"
115 "int $3" /* we never return here */ );
116 #elif defined(__i386__) && defined(_MSC_VER)
117 __declspec(naked) void wine_switch_to_stack( void (*func)(void *), void *arg, void *stack )
119 __asm mov ecx, 4[esp];
120 __asm mov edx, 8[esp];
121 __asm mov esp, 12[esp];
122 __asm push edx;
123 __asm xor ebp, ebp;
124 __asm call [ecx];
125 __asm int 3;
127 #elif defined(__sparc__) && defined(__GNUC__)
128 __ASM_GLOBAL_FUNC( wine_switch_to_stack,
129 "mov %o0, %l0\n\t" /* store first argument */
130 "mov %o1, %l1\n\t" /* store second argument */
131 "mov %o2, %sp\n\t" /* store stack */
132 "call %l0, 0\n\t" /* call func */
133 "mov %l1, %o0\n\t" /* delay slot: arg for func */
134 "ta 0x01"); /* breakpoint - we never get here */
135 #elif defined(__powerpc__) && defined(__APPLE__)
136 __ASM_GLOBAL_FUNC( wine_switch_to_stack,
137 "mtctr r3\n\t" /* func -> ctr */
138 "mr r3,r4\n\t" /* args -> function param 1 (r3) */
139 "mr r1,r5\n\t" /* stack */
140 "bctr\n" /* call ctr */
141 "1:\tb 1b"); /* loop */
142 #elif defined(__powerpc__) && defined(__GNUC__)
143 __ASM_GLOBAL_FUNC( wine_switch_to_stack,
144 "mtctr 3\n\t" /* func -> ctr */
145 "mr 3,4\n\t" /* args -> function param 1 (r3) */
146 "mr 1,5\n\t" /* stack */
147 "bctr\n\t" /* call ctr */
148 "1:\tb 1b"); /* loop */
149 #else
150 #error You must implement wine_switch_to_stack for your platform
151 #endif
154 static char *pe_area;
155 static size_t pe_area_size;
157 /***********************************************************************
158 * wine_set_pe_load_area
160 * Define the reserved area to use for loading the main PE binary.
162 void wine_set_pe_load_area( void *base, size_t size )
164 unsigned int page_mask = getpagesize() - 1;
165 char *end = (char *)base + size;
167 pe_area = (char *)(((unsigned long)base + page_mask) & ~page_mask);
168 pe_area_size = (end - pe_area) & ~page_mask;
172 /***********************************************************************
173 * wine_free_pe_load_area
175 * Free the reserved area to use for loading the main PE binary.
177 void wine_free_pe_load_area(void)
179 #ifdef HAVE_MMAP
180 if (pe_area) munmap( pe_area, pe_area_size );
181 #endif
182 pe_area = NULL;
186 #if (defined(__svr4__) || defined(__NetBSD__)) && !defined(MAP_TRYFIXED)
187 /***********************************************************************
188 * try_mmap_fixed
190 * The purpose of this routine is to emulate the behaviour of
191 * the Linux mmap() routine if a non-NULL address is passed,
192 * but the MAP_FIXED flag is not set. Linux in this case tries
193 * to place the mapping at the specified address, *unless* the
194 * range is already in use. Solaris, however, completely ignores
195 * the address argument in this case.
197 * As Wine code occasionally relies on the Linux behaviour, e.g. to
198 * be able to map non-relocateable PE executables to their proper
199 * start addresses, or to map the DOS memory to 0, this routine
200 * emulates the Linux behaviour by checking whether the desired
201 * address range is still available, and placing the mapping there
202 * using MAP_FIXED if so.
204 static int try_mmap_fixed (void *addr, size_t len, int prot, int flags,
205 int fildes, off_t off)
207 char * volatile result = NULL;
208 int pagesize = getpagesize();
209 pid_t pid;
211 /* We only try to map to a fixed address if
212 addr is non-NULL and properly aligned,
213 and MAP_FIXED isn't already specified. */
215 if ( !addr )
216 return 0;
217 if ( (uintptr_t)addr & (pagesize-1) )
218 return 0;
219 if ( flags & MAP_FIXED )
220 return 0;
222 /* We use vfork() to freeze all threads of the
223 current process. This allows us to check without
224 race condition whether the desired memory range is
225 already in use. Note that because vfork() shares
226 the address spaces between parent and child, we
227 can actually perform the mapping in the child. */
229 if ( (pid = vfork()) == -1 )
231 perror("try_mmap_fixed: vfork");
232 exit(1);
234 if ( pid == 0 )
236 int i;
237 char vec;
239 /* We call mincore() for every page in the desired range.
240 If any of these calls succeeds, the page is already
241 mapped and we must fail. */
242 for ( i = 0; i < len; i += pagesize )
243 if ( mincore( (caddr_t)addr + i, pagesize, &vec ) != -1 )
244 _exit(1);
246 /* Perform the mapping with MAP_FIXED set. This is safe
247 now, as none of the pages is currently in use. */
248 result = mmap( addr, len, prot, flags | MAP_FIXED, fildes, off );
249 if ( result == addr )
250 _exit(0);
252 if ( result != (void *) -1 ) /* This should never happen ... */
253 munmap( result, len );
255 _exit(1);
258 /* vfork() lets the parent continue only after the child
259 has exited. Furthermore, Wine sets SIGCHLD to SIG_IGN,
260 so we don't need to wait for the child. */
262 return result == addr;
264 #endif /* (__svr4__ || __NetBSD__) && !MAP_TRYFIXED */
267 /***********************************************************************
268 * wine_anon_mmap
270 * Portable wrapper for anonymous mmaps
272 void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
274 #ifdef HAVE_MMAP
275 static int fdzero = -1;
277 #ifdef MAP_ANON
278 flags |= MAP_ANON;
279 #else
280 if (fdzero == -1)
282 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
284 perror( "/dev/zero: open" );
285 exit(1);
288 #endif /* MAP_ANON */
290 #ifdef MAP_SHARED
291 flags &= ~MAP_SHARED;
292 #endif
294 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
295 #ifdef MAP_PRIVATE
296 flags |= MAP_PRIVATE;
297 #endif
299 if (pe_area && start &&
300 (char *)start >= pe_area &&
301 (char *)start + size <= pe_area + pe_area_size)
303 wine_free_pe_load_area();
304 flags |= MAP_FIXED;
307 if (!(flags & MAP_FIXED))
309 #ifdef MAP_TRYFIXED
310 /* If available, this will attempt a fixed mapping in-kernel */
311 flags |= MAP_TRYFIXED;
312 #elif defined(__svr4__) || defined(__NetBSD__)
313 if ( try_mmap_fixed( start, size, prot, flags, fdzero, 0 ) )
314 return start;
315 #endif
317 return mmap( start, size, prot, flags, fdzero, 0 );
318 #else
319 return (void *)-1;
320 #endif