2 * Win32 builtin functions
4 * Copyright 1997 Alexandre Julliard
14 #include "builtin32.h"
21 #include "debugtools.h"
23 DEFAULT_DEBUG_CHANNEL(module
);
24 DECLARE_DEBUG_CHANNEL(relay
);
28 BYTE call
; /* 0xe8 call callfrom32 (relative) */
29 DWORD callfrom32 WINE_PACKED
; /* RELAY_CallFrom32 relative addr */
30 BYTE ret
; /* 0xc2 ret $n or 0xc3 ret */
31 WORD args
; /* nb of args to remove from the stack */
37 const DWORD nresources
;
38 const DWORD restabsize
;
39 const IMAGE_RESOURCE_DATA_ENTRY
*entries
;
44 static const BUILTIN32_DESCRIPTOR
*builtin_dlls
[MAX_DLLS
];
45 static HMODULE dll_modules
[MAX_DLLS
];
48 extern void RELAY_CallFrom32();
49 extern void RELAY_CallFrom32Regs();
52 /***********************************************************************
53 * BUILTIN32_WarnSecondInstance
55 * Emit a warning when we are creating a second instance for a DLL
56 * that is known to not support this.
58 static void BUILTIN32_WarnSecondInstance( const char *name
)
60 static const char * const warning_list
[] =
61 { "comctl32", "comdlg32", "crtdll", "imagehlp", "msacm32", "shell32", NULL
};
63 const char * const *ptr
= warning_list
;
67 if (!strcasecmp( *ptr
, name
))
69 ERR( "Attempt to instantiate built-in dll '%s' twice "
70 "in the same address space. Expect trouble!\n", name
);
77 /***********************************************************************
78 * BUILTIN32_DoLoadImage
80 * Load a built-in Win32 module. Helper function for BUILTIN32_LoadImage.
82 static HMODULE
BUILTIN32_DoLoadImage( const BUILTIN32_DESCRIPTOR
*descr
)
85 IMAGE_DATA_DIRECTORY
*dir
;
86 IMAGE_DOS_HEADER
*dos
;
88 IMAGE_SECTION_HEADER
*sec
;
89 IMAGE_EXPORT_DIRECTORY
*exp
;
90 IMAGE_IMPORT_DESCRIPTOR
*imp
;
94 DEBUG_ENTRY_POINT
*debug
;
95 INT i
, size
, nb_sections
;
98 /* Allocate the module */
100 nb_sections
= 2; /* exports + code */
101 if (descr
->nb_imports
) nb_sections
++;
102 size
= (sizeof(IMAGE_DOS_HEADER
)
103 + sizeof(IMAGE_NT_HEADERS
)
104 + nb_sections
* sizeof(IMAGE_SECTION_HEADER
)
105 + (descr
->nb_imports
+1) * sizeof(IMAGE_IMPORT_DESCRIPTOR
)
106 + sizeof(IMAGE_EXPORT_DIRECTORY
)
107 + descr
->nb_funcs
* sizeof(LPVOID
)
108 + descr
->nb_names
* sizeof(LPSTR
)
111 if (WARN_ON(relay
) || TRACE_ON(relay
))
112 size
+= descr
->nb_funcs
* sizeof(DEBUG_ENTRY_POINT
);
114 addr
= VirtualAlloc( NULL
, size
, MEM_COMMIT
, PAGE_EXECUTE_READWRITE
);
116 dos
= (IMAGE_DOS_HEADER
*)addr
;
117 nt
= (IMAGE_NT_HEADERS
*)(dos
+ 1);
118 sec
= (IMAGE_SECTION_HEADER
*)(nt
+ 1);
119 imp
= (IMAGE_IMPORT_DESCRIPTOR
*)(sec
+ nb_sections
);
120 exp
= (IMAGE_EXPORT_DIRECTORY
*)(imp
+ descr
->nb_imports
+ 1);
121 funcs
= (LPVOID
*)(exp
+ 1);
122 names
= (LPSTR
*)(funcs
+ descr
->nb_funcs
);
123 pfwd
= (LPSTR
)(names
+ descr
->nb_names
);
124 debug
= (DEBUG_ENTRY_POINT
*)(pfwd
+ descr
->fwd_size
);
126 /* Build the DOS and NT headers */
128 dos
->e_magic
= IMAGE_DOS_SIGNATURE
;
129 dos
->e_lfanew
= sizeof(*dos
);
131 nt
->Signature
= IMAGE_NT_SIGNATURE
;
132 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_I386
;
133 nt
->FileHeader
.NumberOfSections
= nb_sections
;
134 nt
->FileHeader
.SizeOfOptionalHeader
= sizeof(nt
->OptionalHeader
);
135 nt
->FileHeader
.Characteristics
= descr
->characteristics
;
137 nt
->OptionalHeader
.Magic
= IMAGE_NT_OPTIONAL_HDR_MAGIC
;
138 nt
->OptionalHeader
.SizeOfCode
= 0x1000;
139 nt
->OptionalHeader
.SizeOfInitializedData
= 0;
140 nt
->OptionalHeader
.SizeOfUninitializedData
= 0;
141 nt
->OptionalHeader
.ImageBase
= (DWORD
)addr
;
142 nt
->OptionalHeader
.SectionAlignment
= 0x1000;
143 nt
->OptionalHeader
.FileAlignment
= 0x1000;
144 nt
->OptionalHeader
.MajorOperatingSystemVersion
= 1;
145 nt
->OptionalHeader
.MinorOperatingSystemVersion
= 0;
146 nt
->OptionalHeader
.MajorSubsystemVersion
= 4;
147 nt
->OptionalHeader
.MinorSubsystemVersion
= 0;
148 nt
->OptionalHeader
.SizeOfImage
= size
;
149 nt
->OptionalHeader
.SizeOfHeaders
= (BYTE
*)exp
- addr
;
150 nt
->OptionalHeader
.NumberOfRvaAndSizes
= IMAGE_NUMBEROF_DIRECTORY_ENTRIES
;
151 if (descr
->dllentrypoint
)
152 nt
->OptionalHeader
.AddressOfEntryPoint
= (DWORD
)descr
->dllentrypoint
- (DWORD
)addr
;
154 /* Build the code section */
156 strcpy( sec
->Name
, ".code" );
157 sec
->SizeOfRawData
= 0;
159 if (WARN_ON(relay
) || TRACE_ON(relay
))
160 sec
->SizeOfRawData
+= descr
->nb_funcs
* sizeof(DEBUG_ENTRY_POINT
);
162 sec
->Misc
.VirtualSize
= sec
->SizeOfRawData
;
163 sec
->VirtualAddress
= (BYTE
*)debug
- addr
;
164 sec
->PointerToRawData
= (BYTE
*)debug
- addr
;
165 sec
->Characteristics
= (IMAGE_SCN_CNT_INITIALIZED_DATA
|
166 IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
);
169 /* Build the import directory */
171 if (descr
->nb_imports
)
173 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_IMPORT_DIRECTORY
];
174 dir
->VirtualAddress
= (BYTE
*)imp
- addr
;
175 dir
->Size
= sizeof(*imp
) * (descr
->nb_imports
+ 1);
177 /* Build the imports section */
178 strcpy( sec
->Name
, ".idata" );
179 sec
->Misc
.VirtualSize
= dir
->Size
;
180 sec
->VirtualAddress
= (BYTE
*)imp
- addr
;
181 sec
->SizeOfRawData
= dir
->Size
;
182 sec
->PointerToRawData
= (BYTE
*)imp
- addr
;
183 sec
->Characteristics
= (IMAGE_SCN_CNT_INITIALIZED_DATA
|
184 IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
|
185 IMAGE_SCN_MEM_WRITE
);
188 /* Build the imports */
189 for (i
= 0; i
< descr
->nb_imports
; i
++)
191 imp
[i
].u
.Characteristics
= 0;
192 imp
[i
].ForwarderChain
= -1;
193 imp
[i
].Name
= (BYTE
*)descr
->imports
[i
] - addr
;
194 /* hack: make first thunk point to some zero value */
195 imp
[i
].FirstThunk
= (PIMAGE_THUNK_DATA
)((BYTE
*)&imp
[i
].u
.Characteristics
- addr
);
199 /* Build the export directory */
201 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_EXPORT_DIRECTORY
];
202 dir
->VirtualAddress
= (BYTE
*)exp
- addr
;
203 dir
->Size
= sizeof(*exp
)
204 + descr
->nb_funcs
* sizeof(LPVOID
)
205 + descr
->nb_names
* sizeof(LPSTR
)
208 /* Build the exports section */
210 strcpy( sec
->Name
, ".edata" );
211 sec
->Misc
.VirtualSize
= dir
->Size
;
212 sec
->VirtualAddress
= (BYTE
*)exp
- addr
;
213 sec
->SizeOfRawData
= dir
->Size
;
214 sec
->PointerToRawData
= (BYTE
*)exp
- addr
;
215 sec
->Characteristics
= (IMAGE_SCN_CNT_INITIALIZED_DATA
|
216 IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
|
217 IMAGE_SCN_MEM_WRITE
);
220 /* Build the resource directory */
223 const BUILTIN32_RESOURCE
*rsrc
= descr
->rsrc
;
226 IMAGE_RESOURCE_DATA_ENTRY
*rdep
;
228 rtab
= HeapAlloc(GetProcessHeap(), 0, rsrc
->restabsize
);
231 ERR("Failed to get memory for resource directory\n");
232 VirtualFree(addr
, size
, MEM_RELEASE
);
237 * The resource directory has to be copied because it contains
238 * RVAs. These would be invalid if the dll is instantiated twice.
240 memcpy(rtab
, rsrc
->restab
, rsrc
->restabsize
);
242 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_RESOURCE_DIRECTORY
];
243 dir
->VirtualAddress
= (DWORD
)rtab
- (DWORD
)addr
;
244 dir
->Size
= rsrc
->restabsize
;
245 rdep
= (IMAGE_RESOURCE_DATA_ENTRY
*)((DWORD
)rtab
+ (DWORD
)rsrc
->entries
- (DWORD
)rsrc
->restab
);
246 for(i
= 0; i
< rsrc
->nresources
; i
++)
248 rdep
[i
].OffsetToData
+= (DWORD
)rsrc
->restab
- (DWORD
)addr
;
252 /* Build the exports section data */
254 exp
->Name
= ((BYTE
*)descr
->name
) - addr
; /*??*/
255 exp
->Base
= descr
->base
;
256 exp
->NumberOfFunctions
= descr
->nb_funcs
;
257 exp
->NumberOfNames
= descr
->nb_names
;
258 exp
->AddressOfFunctions
= (LPDWORD
*)((BYTE
*)funcs
- addr
);
259 exp
->AddressOfNames
= (LPDWORD
*)((BYTE
*)names
- addr
);
260 exp
->AddressOfNameOrdinals
= (LPWORD
*)((BYTE
*)descr
->ordinals
- addr
);
262 /* Build the funcs table */
264 for (i
= 0; i
< descr
->nb_funcs
; i
++, funcs
++, debug
++)
266 BYTE args
= descr
->args
[i
];
269 if (!descr
->functions
[i
]) continue;
271 if (args
== 0xfd) /* forward func */
273 strcpy( pfwd
, (LPSTR
)descr
->functions
[i
] );
274 *funcs
= (LPVOID
)((BYTE
*)pfwd
- addr
);
275 pfwd
+= strlen(pfwd
) + 1;
277 else *funcs
= (LPVOID
)((BYTE
*)descr
->functions
[i
] - addr
);
280 if (!(WARN_ON(relay
) || TRACE_ON(relay
))) continue;
281 for (j
=0;j
<descr
->nb_names
;j
++)
282 if (descr
->ordinals
[j
] == i
)
284 if (j
<descr
->nb_names
) {
285 if (descr
->names
[j
]) {
287 sprintf(buffer
,"%s.%d: %s",descr
->name
,i
,descr
->names
[j
]);
288 if (!RELAY_ShowDebugmsgRelay(buffer
))
294 case 0xfd: /* forward */
295 case 0xff: /* stub or extern */
297 default: /* normal function (stdcall or cdecl or register) */
298 if (TRACE_ON(relay
)) {
299 debug
->call
= 0xe8; /* lcall relative */
300 if (args
& 0x40) /* register func */
301 debug
->callfrom32
= (DWORD
)RELAY_CallFrom32Regs
-
304 debug
->callfrom32
= (DWORD
)RELAY_CallFrom32
-
307 debug
->call
= 0xe9; /* ljmp relative */
308 debug
->callfrom32
= (DWORD
)descr
->functions
[i
] -
311 debug
->ret
= (args
& 0x80) ? 0xc3 : 0xc2; /*ret/ret $n*/
312 debug
->args
= (args
& 0x3f) * sizeof(int);
313 *funcs
= (LPVOID
)((BYTE
*)debug
- addr
);
316 #endif /* __i386__ */
319 /* Build the names table */
321 for (i
= 0; i
< exp
->NumberOfNames
; i
++, names
++)
323 *names
= (LPSTR
)((BYTE
*)descr
->names
[i
] - addr
);
325 return (HMODULE
)addr
;
328 /***********************************************************************
329 * BUILTIN32_LoadLibraryExA
331 * Partly copied from the original PE_ version.
334 WINE_MODREF
*BUILTIN32_LoadLibraryExA(LPCSTR path
, DWORD flags
, DWORD
*err
)
339 char dllname
[MAX_PATH
], *p
;
342 /* Fix the name in case we have a full path and extension */
343 if ((p
= strrchr( path
, '\\' ))) path
= p
+ 1;
344 lstrcpynA( dllname
, path
, sizeof(dllname
) );
346 p
= strrchr( dllname
, '.' );
347 if (!p
) strcat( dllname
, ".dll" );
349 /* Search built-in descriptor */
350 for (i
= 0; i
< nb_dlls
; i
++)
351 if (!lstrcmpiA( builtin_dlls
[i
]->filename
, dllname
)) break;
355 *err
= ERROR_FILE_NOT_FOUND
;
359 /* Load built-in module */
362 if (!(dll_modules
[i
] = BUILTIN32_DoLoadImage( builtin_dlls
[i
] )))
364 *err
= ERROR_FILE_NOT_FOUND
;
368 else BUILTIN32_WarnSecondInstance( builtin_dlls
[i
]->name
);
370 /* Create 16-bit dummy module */
371 if ((hModule16
= MODULE_CreateDummyModule( dllname
, 0 )) < 32)
373 *err
= (DWORD
)hModule16
;
374 return NULL
; /* FIXME: Should unload the builtin module */
377 pModule
= (NE_MODULE
*)GlobalLock16( hModule16
);
378 pModule
->flags
= NE_FFLAGS_LIBMODULE
| NE_FFLAGS_SINGLEDATA
| NE_FFLAGS_WIN32
| NE_FFLAGS_BUILTIN
;
379 pModule
->module32
= dll_modules
[i
];
381 /* Create 32-bit MODREF */
382 if ( !(wm
= PE_CreateModule( pModule
->module32
, dllname
, flags
, TRUE
)) )
384 ERR( "can't load %s\n", path
);
385 FreeLibrary16( hModule16
); /* FIXME: Should unload the builtin module */
386 *err
= ERROR_OUTOFMEMORY
;
390 if (wm
->binfmt
.pe
.pe_export
)
391 SNOOP_RegisterDLL(wm
->module
,wm
->modname
,wm
->binfmt
.pe
.pe_export
->NumberOfFunctions
);
397 /***********************************************************************
398 * BUILTIN32_LoadExeModule
400 HMODULE16
BUILTIN32_LoadExeModule( void )
406 /* Search built-in EXE descriptor */
407 for ( i
= 0; i
< nb_dlls
; i
++ )
408 if ( !(builtin_dlls
[i
]->characteristics
& IMAGE_FILE_DLL
) )
412 MESSAGE( "More than one built-in EXE module loaded!\n" );
421 MESSAGE( "No built-in EXE module loaded! Did you create a .spec file?\n" );
425 /* Load built-in module */
426 if ( !dll_modules
[exe
] )
427 if ( !(dll_modules
[exe
] = BUILTIN32_DoLoadImage( builtin_dlls
[exe
] )) )
430 /* Create 16-bit dummy module */
431 hModule16
= MODULE_CreateDummyModule( builtin_dlls
[exe
]->filename
, 0 );
432 if ( hModule16
< 32 ) return 0;
433 pModule
= (NE_MODULE
*)GlobalLock16( hModule16
);
434 pModule
->flags
= NE_FFLAGS_SINGLEDATA
| NE_FFLAGS_WIN32
| NE_FFLAGS_BUILTIN
;
435 pModule
->module32
= dll_modules
[exe
];
441 /***********************************************************************
442 * BUILTIN32_UnloadLibrary
444 * Unload the built-in library and free the modref.
446 void BUILTIN32_UnloadLibrary(WINE_MODREF
*wm
)
448 /* FIXME: do something here */
452 /***********************************************************************
453 * BUILTIN32_GetEntryPoint
455 * Return the name of the DLL entry point corresponding
456 * to a relay entry point address. This is used only by relay debugging.
458 * This function _must_ return the real entry point to call
459 * after the debug info is printed.
461 ENTRYPOINT32
BUILTIN32_GetEntryPoint( char *buffer
, void *relay
,
462 unsigned int *typemask
)
464 const BUILTIN32_DESCRIPTOR
*descr
= NULL
;
467 /* First find the module */
469 for (i
= 0; i
< nb_dlls
; i
++)
472 IMAGE_SECTION_HEADER
*sec
= PE_SECTIONS(dll_modules
[i
]);
473 DEBUG_ENTRY_POINT
*debug
=
474 (DEBUG_ENTRY_POINT
*)((DWORD
)dll_modules
[i
] + sec
[0].VirtualAddress
);
475 DEBUG_ENTRY_POINT
*func
= (DEBUG_ENTRY_POINT
*)relay
;
476 descr
= builtin_dlls
[i
];
477 if (debug
<= func
&& func
< debug
+ descr
->nb_funcs
)
479 ordinal
= func
- debug
;
484 if (!descr
) return NULL
;
486 /* Now find the function */
488 for (i
= 0; i
< descr
->nb_names
; i
++)
489 if (descr
->ordinals
[i
] == ordinal
) break;
491 sprintf( buffer
, "%s.%d: %s", descr
->name
, ordinal
+ descr
->base
,
492 (i
< descr
->nb_names
) ? descr
->names
[i
] : "@" );
493 *typemask
= descr
->argtypes
[ordinal
];
494 return descr
->functions
[ordinal
];
497 /***********************************************************************
498 * BUILTIN32_SwitchRelayDebug
500 * FIXME: enhance to do it module relative.
502 void BUILTIN32_SwitchRelayDebug(BOOL onoff
)
504 const BUILTIN32_DESCRIPTOR
*descr
;
505 IMAGE_SECTION_HEADER
*sec
;
506 DEBUG_ENTRY_POINT
*debug
;
510 if (!(TRACE_ON(relay
) || WARN_ON(relay
)))
512 for (j
= 0; j
< nb_dlls
; j
++)
514 if (!dll_modules
[j
]) continue;
515 sec
= PE_SECTIONS(dll_modules
[j
]);
516 debug
= (DEBUG_ENTRY_POINT
*)((DWORD
)dll_modules
[j
] + sec
[1].VirtualAddress
);
517 descr
= builtin_dlls
[j
];
518 for (i
= 0; i
< descr
->nb_funcs
; i
++,debug
++) {
519 if (!descr
->functions
[i
]) continue;
520 if ((descr
->args
[i
]==0xff) || (descr
->args
[i
]==0xfe))
523 debug
->call
= 0xe8; /* lcall relative */
524 debug
->callfrom32
= (DWORD
)RELAY_CallFrom32
-
527 debug
->call
= 0xe9; /* ljmp relative */
528 debug
->callfrom32
= (DWORD
)descr
->functions
[i
] -
533 #endif /* __i386__ */
537 /***********************************************************************
538 * BUILTIN32_RegisterDLL
540 * Register a built-in DLL descriptor.
542 void BUILTIN32_RegisterDLL( const BUILTIN32_DESCRIPTOR
*descr
)
544 assert( nb_dlls
< MAX_DLLS
);
545 builtin_dlls
[nb_dlls
++] = descr
;
548 /***********************************************************************
549 * BUILTIN32_Unimplemented
551 * This function is called for unimplemented 32-bit entry points (declared
552 * as 'stub' in the spec file).
554 void BUILTIN32_Unimplemented( const BUILTIN32_DESCRIPTOR
*descr
, int ordinal
)
556 const char *func_name
= "???";
559 __RESTORE_ES
; /* Just in case */
561 for (i
= 0; i
< descr
->nb_names
; i
++)
562 if (descr
->ordinals
[i
] + descr
->base
== ordinal
) break;
563 if (i
< descr
->nb_names
) func_name
= descr
->names
[i
];
565 MESSAGE( "No handler for Win32 routine %s.%d: %s",
566 descr
->name
, ordinal
, func_name
);
568 MESSAGE( " (called from %p)", __builtin_return_address(1) );