Rounds to the lowest integer, not the nearest.
[wine.git] / relay32 / builtin32.c
blobc8face610b1da173ba6873262bf9739f66a805b6
1 /*
2 * Win32 builtin functions
4 * Copyright 1997 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <string.h>
9 #include <ctype.h>
10 #include "winuser.h"
11 #include "builtin32.h"
12 #include "peexe.h"
13 #include "neexe.h"
14 #include "heap.h"
15 #include "main.h"
16 #include "snoop.h"
17 #include "winerror.h"
18 #include "debugtools.h"
20 DEFAULT_DEBUG_CHANNEL(module);
21 DECLARE_DEBUG_CHANNEL(relay);
23 typedef struct
25 BYTE call; /* 0xe8 call callfrom32 (relative) */
26 DWORD callfrom32 WINE_PACKED; /* RELAY_CallFrom32 relative addr */
27 BYTE ret; /* 0xc2 ret $n or 0xc3 ret */
28 WORD args; /* nb of args to remove from the stack */
29 } DEBUG_ENTRY_POINT;
31 typedef struct
33 const BYTE *restab;
34 const DWORD nresources;
35 const DWORD restabsize;
36 const IMAGE_RESOURCE_DATA_ENTRY *entries;
37 } BUILTIN32_RESOURCE;
39 #define MAX_DLLS 60
41 static const BUILTIN32_DESCRIPTOR *builtin_dlls[MAX_DLLS];
42 static HMODULE dll_modules[MAX_DLLS];
43 static int nb_dlls;
45 extern void RELAY_CallFrom32();
46 extern void RELAY_CallFrom32Regs();
49 /***********************************************************************
50 * BUILTIN32_WarnSecondInstance
52 * Emit a warning when we are creating a second instance for a DLL
53 * that is known to not support this.
55 static void BUILTIN32_WarnSecondInstance( const char *name )
57 static const char * const warning_list[] =
58 { "comctl32", "comdlg32", "crtdll", "imagehlp", "msacm32", "shell32", NULL };
60 const char * const *ptr = warning_list;
62 while (*ptr)
64 if (!strcasecmp( *ptr, name ))
66 ERR( "Attempt to instantiate built-in dll '%s' twice "
67 "in the same address space. Expect trouble!\n", name );
68 return;
70 ptr++;
74 /***********************************************************************
75 * BUILTIN32_DoLoadImage
77 * Load a built-in Win32 module. Helper function for BUILTIN32_LoadImage.
79 static HMODULE BUILTIN32_DoLoadImage( const BUILTIN32_DESCRIPTOR *descr )
82 IMAGE_DATA_DIRECTORY *dir;
83 IMAGE_DOS_HEADER *dos;
84 IMAGE_NT_HEADERS *nt;
85 IMAGE_SECTION_HEADER *sec;
86 IMAGE_EXPORT_DIRECTORY *exp;
87 IMAGE_IMPORT_DESCRIPTOR *imp;
88 LPVOID *funcs;
89 LPSTR *names;
90 LPSTR pfwd;
91 DEBUG_ENTRY_POINT *debug;
92 INT i, size, nb_sections;
93 BYTE *addr;
95 /* Allocate the module */
97 nb_sections = 2; /* exports + code */
98 if (descr->nb_imports) nb_sections++;
99 size = (sizeof(IMAGE_DOS_HEADER)
100 + sizeof(IMAGE_NT_HEADERS)
101 + nb_sections * sizeof(IMAGE_SECTION_HEADER)
102 + (descr->nb_imports+1) * sizeof(IMAGE_IMPORT_DESCRIPTOR)
103 + sizeof(IMAGE_EXPORT_DIRECTORY)
104 + descr->nb_funcs * sizeof(LPVOID)
105 + descr->nb_names * sizeof(LPSTR)
106 + descr->fwd_size);
107 #ifdef __i386__
108 if (WARN_ON(relay) || TRACE_ON(relay))
109 size += descr->nb_funcs * sizeof(DEBUG_ENTRY_POINT);
110 #endif
111 addr = VirtualAlloc( NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
112 if (!addr) return 0;
113 dos = (IMAGE_DOS_HEADER *)addr;
114 nt = (IMAGE_NT_HEADERS *)(dos + 1);
115 sec = (IMAGE_SECTION_HEADER *)(nt + 1);
116 imp = (IMAGE_IMPORT_DESCRIPTOR *)(sec + nb_sections);
117 exp = (IMAGE_EXPORT_DIRECTORY *)(imp + descr->nb_imports + 1);
118 funcs = (LPVOID *)(exp + 1);
119 names = (LPSTR *)(funcs + descr->nb_funcs);
120 pfwd = (LPSTR)(names + descr->nb_names);
121 debug = (DEBUG_ENTRY_POINT *)(pfwd + descr->fwd_size);
123 /* Build the DOS and NT headers */
125 dos->e_magic = IMAGE_DOS_SIGNATURE;
126 dos->e_lfanew = sizeof(*dos);
128 nt->Signature = IMAGE_NT_SIGNATURE;
129 nt->FileHeader.Machine = IMAGE_FILE_MACHINE_I386;
130 nt->FileHeader.NumberOfSections = nb_sections;
131 nt->FileHeader.SizeOfOptionalHeader = sizeof(nt->OptionalHeader);
132 nt->FileHeader.Characteristics = IMAGE_FILE_DLL;
134 nt->OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC;
135 nt->OptionalHeader.SizeOfCode = 0x1000;
136 nt->OptionalHeader.SizeOfInitializedData = 0;
137 nt->OptionalHeader.SizeOfUninitializedData = 0;
138 nt->OptionalHeader.ImageBase = (DWORD)addr;
139 nt->OptionalHeader.SectionAlignment = 0x1000;
140 nt->OptionalHeader.FileAlignment = 0x1000;
141 nt->OptionalHeader.MajorOperatingSystemVersion = 1;
142 nt->OptionalHeader.MinorOperatingSystemVersion = 0;
143 nt->OptionalHeader.MajorSubsystemVersion = 4;
144 nt->OptionalHeader.MinorSubsystemVersion = 0;
145 nt->OptionalHeader.SizeOfImage = size;
146 nt->OptionalHeader.SizeOfHeaders = (BYTE *)exp - addr;
147 nt->OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
148 if (descr->dllentrypoint)
149 nt->OptionalHeader.AddressOfEntryPoint = (DWORD)descr->dllentrypoint - (DWORD)addr;
151 /* Build the code section */
153 strcpy( sec->Name, ".code" );
154 sec->SizeOfRawData = 0;
155 #ifdef __i386__
156 if (WARN_ON(relay) || TRACE_ON(relay))
157 sec->SizeOfRawData += descr->nb_funcs * sizeof(DEBUG_ENTRY_POINT);
158 #endif
159 sec->Misc.VirtualSize = sec->SizeOfRawData;
160 sec->VirtualAddress = (BYTE *)debug - addr;
161 sec->PointerToRawData = (BYTE *)debug - addr;
162 sec->Characteristics = (IMAGE_SCN_CNT_INITIALIZED_DATA |
163 IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);
164 sec++;
166 /* Build the import directory */
168 if (descr->nb_imports)
170 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY];
171 dir->VirtualAddress = (BYTE *)imp - addr;
172 dir->Size = sizeof(*imp) * (descr->nb_imports + 1);
174 /* Build the imports section */
175 strcpy( sec->Name, ".idata" );
176 sec->Misc.VirtualSize = dir->Size;
177 sec->VirtualAddress = (BYTE *)imp - addr;
178 sec->SizeOfRawData = dir->Size;
179 sec->PointerToRawData = (BYTE *)imp - addr;
180 sec->Characteristics = (IMAGE_SCN_CNT_INITIALIZED_DATA |
181 IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ |
182 IMAGE_SCN_MEM_WRITE);
183 sec++;
185 /* Build the imports */
186 for (i = 0; i < descr->nb_imports; i++)
188 imp[i].u.Characteristics = 0;
189 imp[i].ForwarderChain = -1;
190 imp[i].Name = (BYTE *)descr->imports[i] - addr;
191 /* hack: make first thunk point to some zero value */
192 imp[i].FirstThunk = (PIMAGE_THUNK_DATA)((BYTE *)&imp[i].u.Characteristics - addr);
196 /* Build the export directory */
198 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
199 dir->VirtualAddress = (BYTE *)exp - addr;
200 dir->Size = sizeof(*exp)
201 + descr->nb_funcs * sizeof(LPVOID)
202 + descr->nb_names * sizeof(LPSTR)
203 + descr->fwd_size;
205 /* Build the exports section */
207 strcpy( sec->Name, ".edata" );
208 sec->Misc.VirtualSize = dir->Size;
209 sec->VirtualAddress = (BYTE *)exp - addr;
210 sec->SizeOfRawData = dir->Size;
211 sec->PointerToRawData = (BYTE *)exp - addr;
212 sec->Characteristics = (IMAGE_SCN_CNT_INITIALIZED_DATA |
213 IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ |
214 IMAGE_SCN_MEM_WRITE);
215 sec++;
217 /* Build the resource directory */
218 if(descr->rsrc)
220 const BUILTIN32_RESOURCE *rsrc = descr->rsrc;
221 int i;
222 void *rtab;
223 IMAGE_RESOURCE_DATA_ENTRY *rdep;
225 rtab = HeapAlloc(GetProcessHeap(), 0, rsrc->restabsize);
226 if(!rtab)
228 ERR("Failed to get memory for resource directory\n");
229 VirtualFree(addr, size, MEM_RELEASE);
230 return 0;
234 * The resource directory has to be copied because it contains
235 * RVAs. These would be invalid if the dll is instantiated twice.
237 memcpy(rtab, rsrc->restab, rsrc->restabsize);
239 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
240 dir->VirtualAddress = (DWORD)rtab - (DWORD)addr;
241 dir->Size = rsrc->restabsize;
242 rdep = (IMAGE_RESOURCE_DATA_ENTRY *)((DWORD)rtab + (DWORD)rsrc->entries - (DWORD)rsrc->restab);
243 for(i = 0; i < rsrc->nresources; i++)
245 rdep[i].OffsetToData += (DWORD)rsrc->restab - (DWORD)addr;
249 /* Build the exports section data */
251 exp->Name = ((BYTE *)descr->name) - addr; /*??*/
252 exp->Base = descr->base;
253 exp->NumberOfFunctions = descr->nb_funcs;
254 exp->NumberOfNames = descr->nb_names;
255 exp->AddressOfFunctions = (LPDWORD *)((BYTE *)funcs - addr);
256 exp->AddressOfNames = (LPDWORD *)((BYTE *)names - addr);
257 exp->AddressOfNameOrdinals = (LPWORD *)((BYTE *)descr->ordinals - addr);
259 /* Build the funcs table */
261 for (i = 0; i < descr->nb_funcs; i++, funcs++, debug++)
263 BYTE args = descr->args[i];
264 int j;
266 if (!descr->functions[i]) continue;
268 if (args == 0xfd) /* forward func */
270 strcpy( pfwd, (LPSTR)descr->functions[i] );
271 *funcs = (LPVOID)((BYTE *)pfwd - addr);
272 pfwd += strlen(pfwd) + 1;
274 else *funcs = (LPVOID)((BYTE *)descr->functions[i] - addr);
276 #ifdef __i386__
277 if (!(WARN_ON(relay) || TRACE_ON(relay))) continue;
278 for (j=0;j<descr->nb_names;j++)
279 if (descr->ordinals[j] == i)
280 break;
281 if (j<descr->nb_names) {
282 if (descr->names[j]) {
283 char buffer[200];
284 sprintf(buffer,"%s.%d: %s",descr->name,i,descr->names[j]);
285 if (!RELAY_ShowDebugmsgRelay(buffer))
286 continue;
289 switch(args)
291 case 0xfd: /* forward */
292 case 0xff: /* stub or extern */
293 break;
294 default: /* normal function (stdcall or cdecl or register) */
295 if (TRACE_ON(relay)) {
296 debug->call = 0xe8; /* lcall relative */
297 if (args & 0x40) /* register func */
298 debug->callfrom32 = (DWORD)RELAY_CallFrom32Regs -
299 (DWORD)&debug->ret;
300 else
301 debug->callfrom32 = (DWORD)RELAY_CallFrom32 -
302 (DWORD)&debug->ret;
303 } else {
304 debug->call = 0xe9; /* ljmp relative */
305 debug->callfrom32 = (DWORD)descr->functions[i] -
306 (DWORD)&debug->ret;
308 debug->ret = (args & 0x80) ? 0xc3 : 0xc2; /*ret/ret $n*/
309 debug->args = (args & 0x3f) * sizeof(int);
310 *funcs = (LPVOID)((BYTE *)debug - addr);
311 break;
313 #endif /* __i386__ */
316 /* Build the names table */
318 for (i = 0; i < exp->NumberOfNames; i++, names++)
319 if (descr->names[i])
320 *names = (LPSTR)((BYTE *)descr->names[i] - addr);
322 return (HMODULE)addr;
325 /***********************************************************************
326 * BUILTIN32_LoadLibraryExA
328 * Partly copied from the original PE_ version.
331 WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags, DWORD *err)
333 HMODULE16 hModule16;
334 NE_MODULE *pModule;
335 WINE_MODREF *wm;
336 char dllname[MAX_PATH], *p;
337 int i;
339 /* Fix the name in case we have a full path and extension */
340 if ((p = strrchr( path, '\\' ))) path = p + 1;
341 lstrcpynA( dllname, path, sizeof(dllname) );
343 p = strrchr( dllname, '.' );
344 if (!p) strcat( dllname, ".dll" );
346 /* Search built-in descriptor */
347 for (i = 0; i < nb_dlls; i++)
348 if (!lstrcmpiA( builtin_dlls[i]->filename, dllname )) break;
350 if (i == nb_dlls)
352 *err = ERROR_FILE_NOT_FOUND;
353 return NULL;
356 /* Load built-in module */
357 if (!dll_modules[i])
359 if (!(dll_modules[i] = BUILTIN32_DoLoadImage( builtin_dlls[i] )))
361 *err = ERROR_FILE_NOT_FOUND;
362 return NULL;
365 else BUILTIN32_WarnSecondInstance( builtin_dlls[i]->name );
367 /* Create 16-bit dummy module */
368 if ((hModule16 = MODULE_CreateDummyModule( dllname, 0 )) < 32)
370 *err = (DWORD)hModule16;
371 return NULL; /* FIXME: Should unload the builtin module */
374 pModule = (NE_MODULE *)GlobalLock16( hModule16 );
375 pModule->flags = NE_FFLAGS_LIBMODULE | NE_FFLAGS_SINGLEDATA | NE_FFLAGS_WIN32 | NE_FFLAGS_BUILTIN;
376 pModule->module32 = dll_modules[i];
378 /* Create 32-bit MODREF */
379 if ( !(wm = PE_CreateModule( pModule->module32, dllname, flags, TRUE )) )
381 ERR( "can't load %s\n", path );
382 FreeLibrary16( hModule16 ); /* FIXME: Should unload the builtin module */
383 *err = ERROR_OUTOFMEMORY;
384 return NULL;
387 if (wm->binfmt.pe.pe_export)
388 SNOOP_RegisterDLL(wm->module,wm->modname,wm->binfmt.pe.pe_export->NumberOfFunctions);
390 *err = 0;
391 return wm;
395 /***********************************************************************
396 * BUILTIN32_UnloadLibrary
398 * Unload the built-in library and free the modref.
400 void BUILTIN32_UnloadLibrary(WINE_MODREF *wm)
402 /* FIXME: do something here */
406 /***********************************************************************
407 * BUILTIN32_GetEntryPoint
409 * Return the name of the DLL entry point corresponding
410 * to a relay entry point address. This is used only by relay debugging.
412 * This function _must_ return the real entry point to call
413 * after the debug info is printed.
415 ENTRYPOINT32 BUILTIN32_GetEntryPoint( char *buffer, void *relay,
416 unsigned int *typemask )
418 const BUILTIN32_DESCRIPTOR *descr = NULL;
419 int ordinal = 0, i;
421 /* First find the module */
423 for (i = 0; i < nb_dlls; i++)
424 if (dll_modules[i])
426 IMAGE_SECTION_HEADER *sec = PE_SECTIONS(dll_modules[i]);
427 DEBUG_ENTRY_POINT *debug =
428 (DEBUG_ENTRY_POINT *)((DWORD)dll_modules[i] + sec[0].VirtualAddress);
429 DEBUG_ENTRY_POINT *func = (DEBUG_ENTRY_POINT *)relay;
430 descr = builtin_dlls[i];
431 if (debug <= func && func < debug + descr->nb_funcs)
433 ordinal = func - debug;
434 break;
438 if (!descr) return NULL;
440 /* Now find the function */
442 for (i = 0; i < descr->nb_names; i++)
443 if (descr->ordinals[i] == ordinal) break;
445 sprintf( buffer, "%s.%d: %s", descr->name, ordinal + descr->base,
446 (i < descr->nb_names) ? descr->names[i] : "@" );
447 *typemask = descr->argtypes[ordinal];
448 return descr->functions[ordinal];
451 /***********************************************************************
452 * BUILTIN32_SwitchRelayDebug
454 * FIXME: enhance to do it module relative.
456 void BUILTIN32_SwitchRelayDebug(BOOL onoff)
458 const BUILTIN32_DESCRIPTOR *descr;
459 IMAGE_SECTION_HEADER *sec;
460 DEBUG_ENTRY_POINT *debug;
461 int i, j;
463 #ifdef __i386__
464 if (!(TRACE_ON(relay) || WARN_ON(relay)))
465 return;
466 for (j = 0; j < nb_dlls; j++)
468 if (!dll_modules[j]) continue;
469 sec = PE_SECTIONS(dll_modules[j]);
470 debug = (DEBUG_ENTRY_POINT *)((DWORD)dll_modules[j] + sec[1].VirtualAddress);
471 descr = builtin_dlls[j];
472 for (i = 0; i < descr->nb_funcs; i++,debug++) {
473 if (!descr->functions[i]) continue;
474 if ((descr->args[i]==0xff) || (descr->args[i]==0xfe))
475 continue;
476 if (onoff) {
477 debug->call = 0xe8; /* lcall relative */
478 debug->callfrom32 = (DWORD)RELAY_CallFrom32 -
479 (DWORD)&debug->ret;
480 } else {
481 debug->call = 0xe9; /* ljmp relative */
482 debug->callfrom32 = (DWORD)descr->functions[i] -
483 (DWORD)&debug->ret;
487 #endif /* __i386__ */
488 return;
491 /***********************************************************************
492 * BUILTIN32_RegisterDLL
494 * Register a built-in DLL descriptor.
496 void BUILTIN32_RegisterDLL( const BUILTIN32_DESCRIPTOR *descr )
498 assert( nb_dlls < MAX_DLLS );
499 builtin_dlls[nb_dlls++] = descr;
502 /***********************************************************************
503 * BUILTIN32_Unimplemented
505 * This function is called for unimplemented 32-bit entry points (declared
506 * as 'stub' in the spec file).
508 void BUILTIN32_Unimplemented( const BUILTIN32_DESCRIPTOR *descr, int ordinal )
510 const char *func_name = "???";
511 int i;
513 __RESTORE_ES; /* Just in case */
515 for (i = 0; i < descr->nb_names; i++)
516 if (descr->ordinals[i] + descr->base == ordinal) break;
517 if (i < descr->nb_names) func_name = descr->names[i];
519 MESSAGE( "No handler for Win32 routine %s.%d: %s",
520 descr->name, ordinal, func_name );
521 #ifdef __GNUC__
522 MESSAGE( " (called from %p)", __builtin_return_address(1) );
523 #endif
524 MESSAGE( "\n" );
525 ExitProcess(1);