2 * Win32 builtin functions
4 * Copyright 1997 Alexandre Julliard
20 #include "builtin32.h"
28 #include "debugtools.h"
29 #include "options.h" /* for argv0 */
31 DEFAULT_DEBUG_CHANNEL(module
);
32 DECLARE_DEBUG_CHANNEL(relay
);
36 BYTE call
; /* 0xe8 call callfrom32 (relative) */
37 DWORD callfrom32 WINE_PACKED
; /* RELAY_CallFrom32 relative addr */
38 BYTE ret
; /* 0xc2 ret $n or 0xc3 ret */
39 WORD args
; /* nb of args to remove from the stack */
45 const DWORD nresources
;
46 const DWORD restabsize
;
47 const IMAGE_RESOURCE_DATA_ENTRY
*entries
;
52 static const BUILTIN32_DESCRIPTOR
*builtin_dlls
[MAX_DLLS
];
53 static HMODULE dll_modules
[MAX_DLLS
];
56 extern void RELAY_CallFrom32();
57 extern void RELAY_CallFrom32Regs();
59 /***********************************************************************
60 * BUILTIN32_WarnSecondInstance
62 * Emit a warning when we are creating a second instance for a DLL
63 * that is known to not support this.
65 static void BUILTIN32_WarnSecondInstance( const char *name
)
67 static const char * const warning_list
[] =
68 { "comctl32", "comdlg32", "crtdll", "imagehlp", "msacm32", "shell32", NULL
};
70 const char * const *ptr
= warning_list
;
74 if (!strcasecmp( *ptr
, name
))
76 ERR( "Attempt to instantiate built-in dll '%s' twice "
77 "in the same address space. Expect trouble!\n", name
);
84 /***********************************************************************
87 void *BUILTIN32_dlopen( const char *name
)
92 if ((p
= strrchr( name
, '/' ))) name
= p
+ 1;
93 if ((p
= strrchr( name
, '\\' ))) name
= p
+ 1;
94 sprintf( buffer
, "lib%s", name
);
95 for (p
= buffer
; *p
; p
++) *p
= tolower(*p
);
96 if ((p
= strrchr( buffer
, '.' )) && (!strcmp( p
, ".dll" ) || !strcmp( p
, ".exe" ))) *p
= 0;
97 strcat( buffer
, ".so" );
99 if (!(handle
= ELFDLL_dlopen( buffer
, RTLD_NOW
)))
100 ERR( "failed to load %s: %s\n", buffer
, dlerror() );
107 /***********************************************************************
110 int BUILTIN32_dlclose( void *handle
)
113 return dlclose( handle
);
117 /***********************************************************************
118 * BUILTIN32_DoLoadImage
120 * Load a built-in Win32 module. Helper function for BUILTIN32_LoadImage.
122 static HMODULE
BUILTIN32_DoLoadImage( const BUILTIN32_DESCRIPTOR
*descr
)
125 IMAGE_DATA_DIRECTORY
*dir
;
126 IMAGE_DOS_HEADER
*dos
;
127 IMAGE_NT_HEADERS
*nt
;
128 IMAGE_SECTION_HEADER
*sec
;
129 IMAGE_EXPORT_DIRECTORY
*exp
;
130 IMAGE_IMPORT_DESCRIPTOR
*imp
;
131 const BUILTIN32_RESOURCE
*rsrc
= descr
->rsrc
;
135 DEBUG_ENTRY_POINT
*debug
;
136 INT i
, size
, nb_sections
;
141 /* Allocate the module */
143 nb_sections
= 2; /* exports + code */
144 if (descr
->nb_imports
) nb_sections
++;
146 if (!strcmp(descr
->name
, "KERNEL32")) {
148 xcnsize
= sizeof(DWORD
);
150 size
= (sizeof(IMAGE_DOS_HEADER
)
151 + sizeof(IMAGE_NT_HEADERS
)
152 + nb_sections
* sizeof(IMAGE_SECTION_HEADER
)
153 + (descr
->nb_imports
+1) * sizeof(IMAGE_IMPORT_DESCRIPTOR
)
154 + sizeof(IMAGE_EXPORT_DIRECTORY
)
155 + descr
->nb_funcs
* sizeof(LPVOID
)
156 + descr
->nb_names
* sizeof(LPSTR
)
161 if (WARN_ON(relay
) || TRACE_ON(relay
))
162 size
+= descr
->nb_funcs
* sizeof(DEBUG_ENTRY_POINT
);
164 if (rsrc
) size
+= rsrc
->restabsize
;
165 addr
= VirtualAlloc( NULL
, size
, MEM_COMMIT
, PAGE_EXECUTE_READWRITE
);
167 dos
= (IMAGE_DOS_HEADER
*)addr
;
168 nt
= (IMAGE_NT_HEADERS
*)(dos
+ 1);
169 sec
= (IMAGE_SECTION_HEADER
*)(nt
+ 1);
170 imp
= (IMAGE_IMPORT_DESCRIPTOR
*)(sec
+ nb_sections
);
171 exp
= (IMAGE_EXPORT_DIRECTORY
*)(imp
+ descr
->nb_imports
+ 1);
172 funcs
= (LPVOID
*)(exp
+ 1);
173 names
= (LPSTR
*)(funcs
+ descr
->nb_funcs
);
174 pfwd
= (LPSTR
)(names
+ descr
->nb_names
);
175 xcnlnk
= pfwd
+ descr
->fwd_size
;
176 rtab
= xcnlnk
+ xcnsize
;
177 debug
= (DEBUG_ENTRY_POINT
*)(rtab
+ (rsrc
? rsrc
->restabsize
: 0));
179 /* Build the DOS and NT headers */
181 dos
->e_magic
= IMAGE_DOS_SIGNATURE
;
182 dos
->e_lfanew
= sizeof(*dos
);
184 nt
->Signature
= IMAGE_NT_SIGNATURE
;
185 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_I386
;
186 nt
->FileHeader
.NumberOfSections
= nb_sections
;
187 nt
->FileHeader
.SizeOfOptionalHeader
= sizeof(nt
->OptionalHeader
);
188 nt
->FileHeader
.Characteristics
= descr
->characteristics
;
190 nt
->OptionalHeader
.Magic
= IMAGE_NT_OPTIONAL_HDR_MAGIC
;
191 nt
->OptionalHeader
.SizeOfCode
= 0x1000;
192 nt
->OptionalHeader
.SizeOfInitializedData
= 0;
193 nt
->OptionalHeader
.SizeOfUninitializedData
= 0;
194 nt
->OptionalHeader
.ImageBase
= (DWORD
)addr
;
195 nt
->OptionalHeader
.SectionAlignment
= 0x1000;
196 nt
->OptionalHeader
.FileAlignment
= 0x1000;
197 nt
->OptionalHeader
.MajorOperatingSystemVersion
= 1;
198 nt
->OptionalHeader
.MinorOperatingSystemVersion
= 0;
199 nt
->OptionalHeader
.MajorSubsystemVersion
= 4;
200 nt
->OptionalHeader
.MinorSubsystemVersion
= 0;
201 nt
->OptionalHeader
.SizeOfImage
= size
;
202 nt
->OptionalHeader
.SizeOfHeaders
= (BYTE
*)exp
- addr
;
203 nt
->OptionalHeader
.NumberOfRvaAndSizes
= IMAGE_NUMBEROF_DIRECTORY_ENTRIES
;
204 if (descr
->dllentrypoint
)
205 nt
->OptionalHeader
.AddressOfEntryPoint
= (DWORD
)descr
->dllentrypoint
- (DWORD
)addr
;
207 /* Build the code section */
209 strcpy( sec
->Name
, ".code" );
210 sec
->SizeOfRawData
= 0;
212 if (WARN_ON(relay
) || TRACE_ON(relay
))
213 sec
->SizeOfRawData
+= descr
->nb_funcs
* sizeof(DEBUG_ENTRY_POINT
);
215 sec
->Misc
.VirtualSize
= sec
->SizeOfRawData
;
216 sec
->VirtualAddress
= (BYTE
*)debug
- addr
;
217 sec
->PointerToRawData
= (BYTE
*)debug
- addr
;
218 sec
->Characteristics
= (IMAGE_SCN_CNT_INITIALIZED_DATA
|
219 IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
);
222 /* Build the import directory */
224 if (descr
->nb_imports
)
226 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_IMPORT_DIRECTORY
];
227 dir
->VirtualAddress
= (BYTE
*)imp
- addr
;
228 dir
->Size
= sizeof(*imp
) * (descr
->nb_imports
+ 1);
230 /* Build the imports section */
231 strcpy( sec
->Name
, ".idata" );
232 sec
->Misc
.VirtualSize
= dir
->Size
;
233 sec
->VirtualAddress
= (BYTE
*)imp
- addr
;
234 sec
->SizeOfRawData
= dir
->Size
;
235 sec
->PointerToRawData
= (BYTE
*)imp
- addr
;
236 sec
->Characteristics
= (IMAGE_SCN_CNT_INITIALIZED_DATA
|
237 IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
|
238 IMAGE_SCN_MEM_WRITE
);
241 /* Build the imports */
242 for (i
= 0; i
< descr
->nb_imports
; i
++)
244 imp
[i
].u
.Characteristics
= 0;
245 imp
[i
].ForwarderChain
= -1;
246 imp
[i
].Name
= (BYTE
*)descr
->imports
[i
] - addr
;
247 /* hack: make first thunk point to some zero value */
248 imp
[i
].FirstThunk
= (PIMAGE_THUNK_DATA
)((BYTE
*)&imp
[i
].u
.Characteristics
- addr
);
252 /* Build the export directory */
254 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_EXPORT_DIRECTORY
];
255 dir
->VirtualAddress
= (BYTE
*)exp
- addr
;
256 dir
->Size
= sizeof(*exp
)
257 + descr
->nb_funcs
* sizeof(LPVOID
)
258 + descr
->nb_names
* sizeof(LPSTR
)
261 /* Build the exports section */
263 strcpy( sec
->Name
, ".edata" );
264 sec
->Misc
.VirtualSize
= dir
->Size
;
265 sec
->VirtualAddress
= (BYTE
*)exp
- addr
;
266 sec
->SizeOfRawData
= dir
->Size
;
267 sec
->PointerToRawData
= (BYTE
*)exp
- addr
;
268 sec
->Characteristics
= (IMAGE_SCN_CNT_INITIALIZED_DATA
|
269 IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
|
270 IMAGE_SCN_MEM_WRITE
);
272 /* Build Wine's .so link section. Those sections are used by the wine debugger to
273 * link a builtin PE header with the corresponding ELF module (from either a
274 * shared library, or the main executable - wine emulator or any winelib program
279 strcpy( sec
->Name
, ".xcnlnk" );
280 sec
->Misc
.VirtualSize
= xcnsize
;
281 sec
->VirtualAddress
= (BYTE
*)xcnlnk
- addr
;
282 sec
->SizeOfRawData
= sec
->Misc
.VirtualSize
;
283 sec
->PointerToRawData
= (BYTE
*)xcnlnk
- addr
;
284 sec
->Characteristics
= (IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_READ
);
286 *(const char**)xcnlnk
= argv0
;
289 /* Build the resource directory */
293 IMAGE_RESOURCE_DATA_ENTRY
*rdep
;
296 * The resource directory has to be copied because it contains
297 * RVAs. These would be invalid if the dll is instantiated twice.
299 memcpy(rtab
, rsrc
->restab
, rsrc
->restabsize
);
301 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_RESOURCE_DIRECTORY
];
302 dir
->VirtualAddress
= (BYTE
*)rtab
- addr
;
303 dir
->Size
= rsrc
->restabsize
;
304 rdep
= (IMAGE_RESOURCE_DATA_ENTRY
*)((DWORD
)rtab
+ (DWORD
)rsrc
->entries
- (DWORD
)rsrc
->restab
);
305 for(i
= 0; i
< rsrc
->nresources
; i
++)
307 rdep
[i
].OffsetToData
+= (DWORD
)rsrc
->restab
- (DWORD
)addr
;
311 /* Build the exports section data */
313 exp
->Name
= ((BYTE
*)descr
->name
) - addr
; /*??*/
314 exp
->Base
= descr
->base
;
315 exp
->NumberOfFunctions
= descr
->nb_funcs
;
316 exp
->NumberOfNames
= descr
->nb_names
;
317 exp
->AddressOfFunctions
= (LPDWORD
*)((BYTE
*)funcs
- addr
);
318 exp
->AddressOfNames
= (LPDWORD
*)((BYTE
*)names
- addr
);
319 exp
->AddressOfNameOrdinals
= (LPWORD
*)((BYTE
*)descr
->ordinals
- addr
);
321 /* Build the funcs table */
323 for (i
= 0; i
< descr
->nb_funcs
; i
++, funcs
++, debug
++)
325 BYTE args
= descr
->args
[i
];
328 if (!descr
->functions
[i
]) continue;
330 if (args
== 0xfd) /* forward func */
332 strcpy( pfwd
, (LPSTR
)descr
->functions
[i
] );
333 *funcs
= (LPVOID
)((BYTE
*)pfwd
- addr
);
334 pfwd
+= strlen(pfwd
) + 1;
336 else *funcs
= (LPVOID
)((BYTE
*)descr
->functions
[i
] - addr
);
339 if (!(WARN_ON(relay
) || TRACE_ON(relay
))) continue;
340 for (j
=0;j
<descr
->nb_names
;j
++)
341 if (descr
->ordinals
[j
] == i
)
343 if (j
<descr
->nb_names
) {
344 if (descr
->names
[j
]) {
346 sprintf(buffer
,"%s.%d: %s",descr
->name
,i
,descr
->names
[j
]);
347 if (!RELAY_ShowDebugmsgRelay(buffer
))
353 case 0xfd: /* forward */
354 case 0xff: /* stub or extern */
356 default: /* normal function (stdcall or cdecl or register) */
357 if (TRACE_ON(relay
)) {
358 debug
->call
= 0xe8; /* lcall relative */
359 if (args
& 0x40) /* register func */
360 debug
->callfrom32
= (DWORD
)RELAY_CallFrom32Regs
-
363 debug
->callfrom32
= (DWORD
)RELAY_CallFrom32
-
366 debug
->call
= 0xe9; /* ljmp relative */
367 debug
->callfrom32
= (DWORD
)descr
->functions
[i
] -
370 debug
->ret
= (args
& 0x80) ? 0xc3 : 0xc2; /*ret/ret $n*/
371 debug
->args
= (args
& 0x3f) * sizeof(int);
372 *funcs
= (LPVOID
)((BYTE
*)debug
- addr
);
375 #endif /* __i386__ */
378 /* Build the names table */
380 for (i
= 0; i
< exp
->NumberOfNames
; i
++, names
++)
382 *names
= (LPSTR
)((BYTE
*)descr
->names
[i
] - addr
);
384 return (HMODULE
)addr
;
387 /***********************************************************************
388 * BUILTIN32_LoadLibraryExA
390 * Partly copied from the original PE_ version.
393 WINE_MODREF
*BUILTIN32_LoadLibraryExA(LPCSTR path
, DWORD flags
)
395 struct load_dll_request
*req
= get_req_buffer();
399 char dllname
[MAX_PATH
], *p
;
403 /* Fix the name in case we have a full path and extension */
404 if ((p
= strrchr( path
, '\\' ))) path
= p
+ 1;
405 lstrcpynA( dllname
, path
, sizeof(dllname
) );
407 p
= strrchr( dllname
, '.' );
408 if (!p
) strcat( dllname
, ".dll" );
410 /* Search built-in descriptor */
411 for (i
= 0; i
< nb_dlls
; i
++)
412 if (!strcasecmp( builtin_dlls
[i
]->filename
, dllname
)) goto found
;
414 if ((handle
= BUILTIN32_dlopen( dllname
)))
416 for (i
= 0; i
< nb_dlls
; i
++)
417 if (!strcasecmp( builtin_dlls
[i
]->filename
, dllname
)) goto found
;
418 ERR( "loaded .so but dll %s still not found\n", dllname
);
419 BUILTIN32_dlclose( handle
);
422 SetLastError( ERROR_FILE_NOT_FOUND
);
426 /* Load built-in module */
429 if (!(dll_modules
[i
] = BUILTIN32_DoLoadImage( builtin_dlls
[i
] ))) return NULL
;
431 else BUILTIN32_WarnSecondInstance( builtin_dlls
[i
]->name
);
433 /* Create 16-bit dummy module */
434 if ((hModule16
= MODULE_CreateDummyModule( dllname
, dll_modules
[i
] )) < 32)
436 SetLastError( (DWORD
)hModule16
);
437 return NULL
; /* FIXME: Should unload the builtin module */
439 pModule
= (NE_MODULE
*)GlobalLock16( hModule16
);
440 pModule
->flags
= NE_FFLAGS_LIBMODULE
| NE_FFLAGS_SINGLEDATA
| NE_FFLAGS_WIN32
| NE_FFLAGS_BUILTIN
;
442 /* Create 32-bit MODREF */
443 if ( !(wm
= PE_CreateModule( pModule
->module32
, dllname
, flags
, TRUE
)) )
445 ERR( "can't load %s\n", path
);
446 FreeLibrary16( hModule16
); /* FIXME: Should unload the builtin module */
447 SetLastError( ERROR_OUTOFMEMORY
);
451 if (wm
->binfmt
.pe
.pe_export
)
452 SNOOP_RegisterDLL(wm
->module
,wm
->modname
,wm
->binfmt
.pe
.pe_export
->NumberOfFunctions
);
455 req
->base
= (void *)pModule
->module32
;
458 req
->name
= &wm
->modname
;
459 server_call_noerr( REQ_LOAD_DLL
);
463 /***********************************************************************
464 * BUILTIN32_LoadExeModule
466 HMODULE
BUILTIN32_LoadExeModule( LPCSTR
*filename
)
470 /* Search built-in EXE descriptor */
471 for ( i
= 0; i
< nb_dlls
; i
++ )
472 if ( !(builtin_dlls
[i
]->characteristics
& IMAGE_FILE_DLL
) )
476 MESSAGE( "More than one built-in EXE module loaded!\n" );
485 MESSAGE( "No built-in EXE module loaded! Did you create a .spec file?\n" );
489 /* Load built-in module */
490 if ( !dll_modules
[exe
] )
491 if ( !(dll_modules
[exe
] = BUILTIN32_DoLoadImage( builtin_dlls
[exe
] )) )
494 *filename
= builtin_dlls
[exe
]->filename
;
495 return dll_modules
[exe
];
499 /***********************************************************************
500 * BUILTIN32_UnloadLibrary
502 * Unload the built-in library and free the modref.
504 void BUILTIN32_UnloadLibrary(WINE_MODREF
*wm
)
506 /* FIXME: do something here */
510 /***********************************************************************
511 * BUILTIN32_GetEntryPoint
513 * Return the name of the DLL entry point corresponding
514 * to a relay entry point address. This is used only by relay debugging.
516 * This function _must_ return the real entry point to call
517 * after the debug info is printed.
519 ENTRYPOINT32
BUILTIN32_GetEntryPoint( char *buffer
, void *relay
,
520 unsigned int *typemask
)
522 const BUILTIN32_DESCRIPTOR
*descr
= NULL
;
525 /* First find the module */
527 for (i
= 0; i
< nb_dlls
; i
++)
530 IMAGE_SECTION_HEADER
*sec
= PE_SECTIONS(dll_modules
[i
]);
531 DEBUG_ENTRY_POINT
*debug
=
532 (DEBUG_ENTRY_POINT
*)((DWORD
)dll_modules
[i
] + sec
[0].VirtualAddress
);
533 DEBUG_ENTRY_POINT
*func
= (DEBUG_ENTRY_POINT
*)relay
;
534 descr
= builtin_dlls
[i
];
535 if (debug
<= func
&& func
< debug
+ descr
->nb_funcs
)
537 ordinal
= func
- debug
;
542 if (!descr
) return NULL
;
544 /* Now find the function */
546 for (i
= 0; i
< descr
->nb_names
; i
++)
547 if (descr
->ordinals
[i
] == ordinal
) break;
549 sprintf( buffer
, "%s.%d: %s", descr
->name
, ordinal
+ descr
->base
,
550 (i
< descr
->nb_names
) ? descr
->names
[i
] : "@" );
551 *typemask
= descr
->argtypes
[ordinal
];
552 return descr
->functions
[ordinal
];
555 /***********************************************************************
556 * BUILTIN32_SwitchRelayDebug
558 * FIXME: enhance to do it module relative.
560 void BUILTIN32_SwitchRelayDebug(BOOL onoff
)
562 const BUILTIN32_DESCRIPTOR
*descr
;
563 IMAGE_SECTION_HEADER
*sec
;
564 DEBUG_ENTRY_POINT
*debug
;
568 if (!(TRACE_ON(relay
) || WARN_ON(relay
)))
570 for (j
= 0; j
< nb_dlls
; j
++)
572 if (!dll_modules
[j
]) continue;
573 sec
= PE_SECTIONS(dll_modules
[j
]);
574 debug
= (DEBUG_ENTRY_POINT
*)((DWORD
)dll_modules
[j
] + sec
[1].VirtualAddress
);
575 descr
= builtin_dlls
[j
];
576 for (i
= 0; i
< descr
->nb_funcs
; i
++,debug
++) {
577 if (!descr
->functions
[i
]) continue;
578 if ((descr
->args
[i
]==0xff) || (descr
->args
[i
]==0xfe))
581 debug
->call
= 0xe8; /* lcall relative */
582 debug
->callfrom32
= (DWORD
)RELAY_CallFrom32
-
585 debug
->call
= 0xe9; /* ljmp relative */
586 debug
->callfrom32
= (DWORD
)descr
->functions
[i
] -
591 #endif /* __i386__ */
595 /***********************************************************************
596 * BUILTIN32_RegisterDLL
598 * Register a built-in DLL descriptor.
600 void BUILTIN32_RegisterDLL( const BUILTIN32_DESCRIPTOR
*descr
)
602 assert( nb_dlls
< MAX_DLLS
);
603 builtin_dlls
[nb_dlls
++] = descr
;
606 /***********************************************************************
607 * BUILTIN32_Unimplemented
609 * This function is called for unimplemented 32-bit entry points (declared
610 * as 'stub' in the spec file).
612 void BUILTIN32_Unimplemented( const BUILTIN32_DESCRIPTOR
*descr
, int ordinal
)
614 const char *func_name
= "???";
617 __RESTORE_ES
; /* Just in case */
619 for (i
= 0; i
< descr
->nb_names
; i
++)
620 if (descr
->ordinals
[i
] + descr
->base
== ordinal
) break;
621 if (i
< descr
->nb_names
) func_name
= descr
->names
[i
];
623 MESSAGE( "No handler for Win32 routine %s.%d: %s",
624 descr
->name
, ordinal
, func_name
);
626 MESSAGE( " (called from %p)", __builtin_return_address(1) );