Build Win32 resources as .res files and dump them into the .spec.c file.
[wine] / relay32 / builtin32.c
1 /*
2  * Win32 builtin functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  */
6
7 #include "config.h"
8
9 #include <assert.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <ctype.h>
13 #ifdef HAVE_DL_API
14 #include <dlfcn.h>
15 #endif
16 #include <sys/types.h>
17 #ifdef HAVE_SYS_MMAN_H
18 #include <sys/mman.h>
19 #endif
20
21 #include "windef.h"
22 #include "wine/winbase16.h"
23 #include "elfdll.h"
24 #include "global.h"
25 #include "neexe.h"
26 #include "heap.h"
27 #include "main.h"
28 #include "winerror.h"
29 #include "server.h"
30 #include "debugtools.h"
31
32 DEFAULT_DEBUG_CHANNEL(module);
33 DECLARE_DEBUG_CHANNEL(relay);
34
35 typedef struct
36 {
37     BYTE                        *restab;
38     DWORD                       nresources;
39     DWORD                       restabsize;
40     IMAGE_RESOURCE_DATA_ENTRY   *entries;
41 } BUILTIN32_RESOURCE;
42
43 #define MAX_DLLS 100
44
45 typedef struct
46 {
47     const IMAGE_NT_HEADERS *nt;           /* NT header */
48     const char             *filename;     /* DLL file name */
49 } BUILTIN32_DESCRIPTOR;
50
51 extern void RELAY_SetupDLL( const char *module );
52
53 static BUILTIN32_DESCRIPTOR builtin_dlls[MAX_DLLS];
54 static int nb_dlls;
55
56
57 /***********************************************************************
58  *           BUILTIN32_dlopen
59  */
60 void *BUILTIN32_dlopen( const char *name )
61 {
62 #ifdef HAVE_DL_API
63     void *handle;
64     char buffer[128], *p;
65     if ((p = strrchr( name, '/' ))) name = p + 1;
66     if ((p = strrchr( name, '\\' ))) name = p + 1;
67     sprintf( buffer, "lib%s", name );
68     for (p = buffer; *p; p++) *p = tolower(*p);
69     if ((p = strrchr( buffer, '.' )) && (!strcmp( p, ".dll" ) || !strcmp( p, ".exe" ))) *p = 0;
70     strcat( buffer, ".so" );
71
72     if (!(handle = ELFDLL_dlopen( buffer, RTLD_NOW )))
73     {
74         LPSTR pErr, p;
75         pErr = dlerror();
76         p = strchr(pErr, ':');
77         if ((p) && 
78            (!strncmp(p, ": undefined symbol", 18))) /* undef symbol -> ERR() */
79             ERR("failed to load %s: %s\n", buffer, pErr);
80         else /* WARN() for libraries that are supposed to be native */
81             WARN("failed to load %s: %s\n", buffer, pErr );
82     }
83     return handle;
84 #else
85     return NULL;
86 #endif
87 }
88
89 /***********************************************************************
90  *           BUILTIN32_dlclose
91  */
92 int BUILTIN32_dlclose( void *handle )
93 {
94 #ifdef HAVE_DL_API
95     /* FIXME: should unregister descriptors first */
96     /* return dlclose( handle ); */
97 #endif
98     return 0;
99 }
100
101
102 /***********************************************************************
103  *           fixup_rva_ptrs
104  *
105  * Adjust an array of pointers to make them into RVAs.
106  */
107 static inline void fixup_rva_ptrs( void *array, void *base, int count )
108 {
109     void **ptr = (void **)array;
110     while (count--)
111     {
112         if (*ptr) *ptr = (void *)((char *)*ptr - (char *)base);
113         ptr++;
114     }
115 }
116
117
118 /***********************************************************************
119  *           fixup_resources
120  */
121 static void fixup_resources( IMAGE_RESOURCE_DIRECTORY *dir, char *root, void *base )
122 {
123     IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
124     int i;
125
126     entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
127     for (i = 0; i < dir->NumberOfNamedEntries + dir->NumberOfIdEntries; i++, entry++)
128     {
129         void *ptr = root + entry->u2.s.OffsetToDirectory;
130         if (entry->u2.s.DataIsDirectory) fixup_resources( ptr, root, base );
131         else
132         {
133             IMAGE_RESOURCE_DATA_ENTRY *data = ptr;
134             fixup_rva_ptrs( &data->OffsetToData, base, 1 );
135         }
136     }
137 }
138
139
140 /***********************************************************************
141  *           BUILTIN32_DoLoadImage
142  *
143  * Load a built-in Win32 module. Helper function for BUILTIN32_LoadImage.
144  */
145 static HMODULE BUILTIN32_DoLoadImage( const BUILTIN32_DESCRIPTOR *descr )
146 {
147     IMAGE_DATA_DIRECTORY *dir;
148     IMAGE_DOS_HEADER *dos;
149     IMAGE_NT_HEADERS *nt;
150     IMAGE_SECTION_HEADER *sec;
151     INT size, nb_sections;
152     BYTE *addr, *code_start, *data_start;
153     int page_size = VIRTUAL_GetPageSize();
154
155     /* Allocate the module */
156
157     nb_sections = 2;  /* code + data */
158
159     size = (sizeof(IMAGE_DOS_HEADER)
160             + sizeof(IMAGE_NT_HEADERS)
161             + nb_sections * sizeof(IMAGE_SECTION_HEADER));
162
163     assert( size <= page_size );
164
165     if (descr->nt->OptionalHeader.ImageBase)
166     {
167         void *base = (void *)descr->nt->OptionalHeader.ImageBase;
168         if ((addr = VIRTUAL_mmap( -1, base, page_size, 0,
169                                   PROT_READ|PROT_WRITE, MAP_FIXED )) != base)
170         {
171             ERR("failed to map over PE header for %s at %p\n", descr->filename, base );
172             return 0;
173         }
174     }
175     else
176     {
177         if (!(addr = VirtualAlloc( NULL, page_size, MEM_COMMIT, PAGE_READWRITE ))) return 0;
178     }
179
180     dos    = (IMAGE_DOS_HEADER *)addr;
181     nt     = (IMAGE_NT_HEADERS *)(dos + 1);
182     sec    = (IMAGE_SECTION_HEADER *)(nt + 1);
183     code_start = addr + page_size;
184
185     /* HACK! */
186     data_start = code_start + page_size;
187
188     /* Build the DOS and NT headers */
189
190     dos->e_magic  = IMAGE_DOS_SIGNATURE;
191     dos->e_lfanew = sizeof(*dos);
192
193     *nt = *descr->nt;
194
195     nt->FileHeader.NumberOfSections                = nb_sections;
196     nt->OptionalHeader.SizeOfCode                  = data_start - code_start;
197     nt->OptionalHeader.SizeOfInitializedData       = 0;
198     nt->OptionalHeader.SizeOfUninitializedData     = 0;
199     nt->OptionalHeader.ImageBase                   = (DWORD)addr;
200
201     fixup_rva_ptrs( &nt->OptionalHeader.AddressOfEntryPoint, addr, 1 );
202
203     /* Build the code section */
204
205     strcpy( sec->Name, ".text" );
206     sec->SizeOfRawData = data_start - code_start;
207     sec->Misc.VirtualSize = sec->SizeOfRawData;
208     sec->VirtualAddress   = code_start - addr;
209     sec->PointerToRawData = code_start - addr;
210     sec->Characteristics  = (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);
211     sec++;
212
213     /* Build the data section */
214
215     strcpy( sec->Name, ".data" );
216     sec->SizeOfRawData = 0;
217     sec->Misc.VirtualSize = sec->SizeOfRawData;
218     sec->VirtualAddress   = data_start - addr;
219     sec->PointerToRawData = data_start - addr;
220     sec->Characteristics  = (IMAGE_SCN_CNT_INITIALIZED_DATA |
221                              IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ);
222     sec++;
223
224     /* Build the import directory */
225
226     dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY];
227     if (dir->Size)
228     {
229         IMAGE_IMPORT_DESCRIPTOR *imports = (void *)dir->VirtualAddress;
230         fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
231         /* we can fixup everything at once since we only have pointers and 0 values */
232         fixup_rva_ptrs( imports, addr, dir->Size / sizeof(void*) );
233     }
234
235     /* Build the resource directory */
236
237     dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
238     if (dir->Size)
239     {
240         void *ptr = (void *)dir->VirtualAddress;
241         fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
242         fixup_resources( ptr, ptr, addr );
243     }
244
245     /* Build the export directory */
246
247     dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
248     if (dir->Size)
249     {
250         IMAGE_EXPORT_DIRECTORY *exports = (void *)dir->VirtualAddress;
251         fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
252         fixup_rva_ptrs( (void *)exports->AddressOfFunctions, addr, exports->NumberOfFunctions );
253         fixup_rva_ptrs( (void *)exports->AddressOfNames, addr, exports->NumberOfNames );
254         fixup_rva_ptrs( &exports->Name, addr, 1 );
255         fixup_rva_ptrs( &exports->AddressOfFunctions, addr, 1 );
256         fixup_rva_ptrs( &exports->AddressOfNames, addr, 1 );
257         fixup_rva_ptrs( &exports->AddressOfNameOrdinals, addr, 1 );
258
259         /* Setup relay debugging entry points */
260         if (WARN_ON(relay) || TRACE_ON(relay)) RELAY_SetupDLL( addr );
261     }
262
263     return (HMODULE)addr;
264 }
265
266 /***********************************************************************
267  *           BUILTIN32_LoadLibraryExA
268  *
269  * Partly copied from the original PE_ version.
270  *
271  */
272 WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags)
273 {
274     HMODULE module;
275     WINE_MODREF   *wm;
276     char dllname[20], *p;
277     LPCSTR name;
278     void *handle;
279     int i;
280
281     /* Fix the name in case we have a full path and extension */
282     name = path;
283     if ((p = strrchr( name, '\\' ))) name = p + 1;
284     if ((p = strrchr( name, '/' ))) name = p + 1;
285
286     if (strlen(name) >= sizeof(dllname)-4) goto error;
287
288     strcpy( dllname, name );
289     p = strrchr( dllname, '.' );
290     if (!p) strcat( dllname, ".dll" );
291
292     /* Search built-in descriptor */
293     for (i = 0; i < nb_dlls; i++)
294         if (!strcasecmp( builtin_dlls[i].filename, dllname )) goto found;
295
296     if ((handle = BUILTIN32_dlopen( dllname )))
297     {
298         for (i = 0; i < nb_dlls; i++)
299             if (!strcasecmp( builtin_dlls[i].filename, dllname )) goto found;
300         ERR( "loaded .so but dll %s still not found\n", dllname );
301         BUILTIN32_dlclose( handle );
302     }
303
304  error:
305     SetLastError( ERROR_FILE_NOT_FOUND );
306     return NULL;
307
308  found:
309     /* Load built-in module */
310     if (!(module = BUILTIN32_DoLoadImage( &builtin_dlls[i] ))) return NULL;
311
312     /* Create 32-bit MODREF */
313     if ( !(wm = PE_CreateModule( module, path, flags, -1, TRUE )) )
314     {
315         ERR( "can't load %s\n", path );
316         SetLastError( ERROR_OUTOFMEMORY );
317         return NULL;
318     }
319
320     wm->refCount++;  /* we don't support freeing builtin dlls (FIXME)*/
321     return wm;
322 }
323
324 /***********************************************************************
325  *           BUILTIN32_LoadExeModule
326  */
327 HMODULE BUILTIN32_LoadExeModule(void)
328 {
329     int i, exe = -1;
330
331     /* Search built-in EXE descriptor */
332     for ( i = 0; i < nb_dlls; i++ )
333         if ( !(builtin_dlls[i].nt->FileHeader.Characteristics & IMAGE_FILE_DLL) )
334         {
335             if ( exe != -1 )
336             {
337                 MESSAGE( "More than one built-in EXE module loaded!\n" );
338                 break;
339             }
340
341             exe = i;
342         }
343
344     if ( exe == -1 ) 
345     {
346         MESSAGE( "No built-in EXE module loaded!  Did you create a .spec file?\n" );
347         return 0;
348     }
349
350     /* Load built-in module */
351     return BUILTIN32_DoLoadImage( &builtin_dlls[exe] );
352 }
353
354
355 /***********************************************************************
356  *           BUILTIN32_RegisterDLL
357  *
358  * Register a built-in DLL descriptor.
359  */
360 void BUILTIN32_RegisterDLL( const IMAGE_NT_HEADERS *header, const char *filename )
361 {
362     assert( nb_dlls < MAX_DLLS );
363     builtin_dlls[nb_dlls].nt = header;
364     builtin_dlls[nb_dlls].filename = filename;
365     nb_dlls++;
366 }
367
368 /***********************************************************************
369  *           BUILTIN32_Unimplemented
370  *
371  * This function is called for unimplemented 32-bit entry points (declared
372  * as 'stub' in the spec file).
373  */
374 void BUILTIN32_Unimplemented( const char *dllname, const char *funcname )
375 {
376     __RESTORE_ES;  /* Just in case */
377
378     MESSAGE( "FATAL: No handler for Win32 routine %s.%s", dllname, funcname );
379 #ifdef __GNUC__
380     MESSAGE( " (called from %p)", __builtin_return_address(1) );
381 #endif
382     MESSAGE( "\n" );
383     ExitProcess(1);
384 }