2 * Win32 builtin functions
4 * Copyright 1997 Alexandre Julliard
16 #ifdef HAVE_SYS_MMAN_H
21 #include "wine/winbase16.h"
24 #include "builtin32.h"
34 #include "debugtools.h"
35 #include "options.h" /* for argv0 */
37 DEFAULT_DEBUG_CHANNEL(module
);
38 DECLARE_DEBUG_CHANNEL(relay
);
45 IMAGE_RESOURCE_DATA_ENTRY
*entries
;
50 static const BUILTIN32_DESCRIPTOR
*builtin_dlls
[MAX_DLLS
];
51 static HMODULE dll_modules
[MAX_DLLS
];
55 /***********************************************************************
56 * BUILTIN32_WarnSecondInstance
58 * Emit a warning when we are creating a second instance for a DLL
59 * that is known to not support this.
61 static void BUILTIN32_WarnSecondInstance( const char *name
)
63 static const char * const warning_list
[] =
64 { "comctl32.dll", "comdlg32.dll", "crtdll.dll",
65 "imagehlp.dll", "msacm32.dll", "shell32.dll", NULL
};
67 const char * const *ptr
= warning_list
;
71 if (!strcasecmp( *ptr
, name
))
73 ERR( "Attempt to instantiate built-in dll '%s' twice "
74 "in the same address space. Expect trouble!\n", name
);
81 /***********************************************************************
84 void *BUILTIN32_dlopen( const char *name
)
89 if ((p
= strrchr( name
, '/' ))) name
= p
+ 1;
90 if ((p
= strrchr( name
, '\\' ))) name
= p
+ 1;
91 sprintf( buffer
, "lib%s", name
);
92 for (p
= buffer
; *p
; p
++) *p
= tolower(*p
);
93 if ((p
= strrchr( buffer
, '.' )) && (!strcmp( p
, ".dll" ) || !strcmp( p
, ".exe" ))) *p
= 0;
94 strcat( buffer
, ".so" );
96 if (!(handle
= ELFDLL_dlopen( buffer
, RTLD_NOW
)))
97 ERR( "failed to load %s: %s\n", buffer
, dlerror() );
104 /***********************************************************************
107 int BUILTIN32_dlclose( void *handle
)
110 /* FIXME: should unregister descriptors first */
111 /* return dlclose( handle ); */
117 /***********************************************************************
120 * Adjust an array of pointers to make them into RVAs.
122 static inline void fixup_rva_ptrs( void *array
, void *base
, int count
)
124 void **ptr
= (void **)array
;
127 if (*ptr
) *ptr
= (void *)((char *)*ptr
- (char *)base
);
133 /***********************************************************************
134 * BUILTIN32_DoLoadImage
136 * Load a built-in Win32 module. Helper function for BUILTIN32_LoadImage.
138 static HMODULE
BUILTIN32_DoLoadImage( const BUILTIN32_DESCRIPTOR
*descr
)
140 IMAGE_DATA_DIRECTORY
*dir
;
141 IMAGE_DOS_HEADER
*dos
;
142 IMAGE_NT_HEADERS
*nt
;
143 IMAGE_SECTION_HEADER
*sec
;
144 IMAGE_IMPORT_DESCRIPTOR
*imp
;
145 IMAGE_EXPORT_DIRECTORY
*exports
= descr
->exports
;
146 INT i
, size
, nb_sections
;
147 BYTE
*addr
, *code_start
, *data_start
;
150 int page_size
= VIRTUAL_GetPageSize();
152 /* Allocate the module */
154 nb_sections
= 2; /* code + data */
156 if (!strcmp(descr
->filename
, "kernel32.dll")) {
158 xcnsize
= sizeof(DWORD
);
160 size
= (sizeof(IMAGE_DOS_HEADER
)
161 + sizeof(IMAGE_NT_HEADERS
)
162 + nb_sections
* sizeof(IMAGE_SECTION_HEADER
)
163 + (descr
->nb_imports
+1) * sizeof(IMAGE_IMPORT_DESCRIPTOR
)
166 assert( size
<= page_size
);
168 if (descr
->pe_header
)
170 if ((addr
= FILE_dommap( -1, descr
->pe_header
, 0, page_size
, 0, 0,
171 PROT_READ
|PROT_WRITE
, MAP_FIXED
)) != descr
->pe_header
)
173 ERR("failed to map over PE header for %s at %p\n", descr
->filename
, descr
->pe_header
);
179 if (!(addr
= VirtualAlloc( NULL
, page_size
, MEM_COMMIT
, PAGE_READWRITE
))) return 0;
182 dos
= (IMAGE_DOS_HEADER
*)addr
;
183 nt
= (IMAGE_NT_HEADERS
*)(dos
+ 1);
184 sec
= (IMAGE_SECTION_HEADER
*)(nt
+ 1);
185 imp
= (IMAGE_IMPORT_DESCRIPTOR
*)(sec
+ nb_sections
);
186 xcnlnk
= (char *)(imp
+ descr
->nb_imports
+ 1);
187 code_start
= addr
+ page_size
;
190 data_start
= code_start
+ page_size
;
192 /* Build the DOS and NT headers */
194 dos
->e_magic
= IMAGE_DOS_SIGNATURE
;
195 dos
->e_lfanew
= sizeof(*dos
);
197 nt
->Signature
= IMAGE_NT_SIGNATURE
;
198 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_I386
;
199 nt
->FileHeader
.NumberOfSections
= nb_sections
;
200 nt
->FileHeader
.SizeOfOptionalHeader
= sizeof(nt
->OptionalHeader
);
201 nt
->FileHeader
.Characteristics
= descr
->characteristics
;
203 nt
->OptionalHeader
.Magic
= IMAGE_NT_OPTIONAL_HDR_MAGIC
;
204 nt
->OptionalHeader
.SizeOfCode
= data_start
- code_start
;
205 nt
->OptionalHeader
.SizeOfInitializedData
= 0;
206 nt
->OptionalHeader
.SizeOfUninitializedData
= 0;
207 nt
->OptionalHeader
.ImageBase
= (DWORD
)addr
;
208 nt
->OptionalHeader
.SectionAlignment
= page_size
;
209 nt
->OptionalHeader
.FileAlignment
= page_size
;
210 nt
->OptionalHeader
.MajorOperatingSystemVersion
= 1;
211 nt
->OptionalHeader
.MinorOperatingSystemVersion
= 0;
212 nt
->OptionalHeader
.MajorSubsystemVersion
= 4;
213 nt
->OptionalHeader
.MinorSubsystemVersion
= 0;
214 nt
->OptionalHeader
.SizeOfImage
= page_size
;
215 nt
->OptionalHeader
.SizeOfHeaders
= page_size
;
216 nt
->OptionalHeader
.NumberOfRvaAndSizes
= IMAGE_NUMBEROF_DIRECTORY_ENTRIES
;
217 if (descr
->dllentrypoint
)
218 nt
->OptionalHeader
.AddressOfEntryPoint
= (DWORD
)descr
->dllentrypoint
- (DWORD
)addr
;
220 /* Build the code section */
222 strcpy( sec
->Name
, ".text" );
223 sec
->SizeOfRawData
= data_start
- code_start
;
224 sec
->Misc
.VirtualSize
= sec
->SizeOfRawData
;
225 sec
->VirtualAddress
= code_start
- addr
;
226 sec
->PointerToRawData
= code_start
- addr
;
227 sec
->Characteristics
= (IMAGE_SCN_CNT_CODE
| IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
);
230 /* Build the data section */
232 strcpy( sec
->Name
, ".data" );
233 sec
->SizeOfRawData
= 0;
234 sec
->Misc
.VirtualSize
= sec
->SizeOfRawData
;
235 sec
->VirtualAddress
= data_start
- addr
;
236 sec
->PointerToRawData
= data_start
- addr
;
237 sec
->Characteristics
= (IMAGE_SCN_CNT_INITIALIZED_DATA
|
238 IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
);
241 /* Build the import directory */
243 if (descr
->nb_imports
)
245 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_IMPORT_DIRECTORY
];
246 dir
->VirtualAddress
= (BYTE
*)imp
- addr
;
247 dir
->Size
= sizeof(*imp
) * (descr
->nb_imports
+ 1);
249 /* Build the imports */
250 for (i
= 0; i
< descr
->nb_imports
; i
++)
252 imp
[i
].u
.Characteristics
= 0;
253 imp
[i
].ForwarderChain
= -1;
254 imp
[i
].Name
= (BYTE
*)descr
->imports
[i
] - addr
;
255 /* hack: make first thunk point to some zero value */
256 imp
[i
].FirstThunk
= (PIMAGE_THUNK_DATA
)((BYTE
*)&imp
[i
].u
.Characteristics
- addr
);
260 /* Build Wine's .so link section. Those sections are used by the wine debugger to
261 * link a builtin PE header with the corresponding ELF module (from either a
262 * shared library, or the main executable - wine emulator or any winelib program
266 strcpy( sec
->Name
, ".xcnlnk" );
267 sec
->Misc
.VirtualSize
= xcnsize
;
268 sec
->VirtualAddress
= (BYTE
*)xcnlnk
- addr
;
269 sec
->SizeOfRawData
= sec
->Misc
.VirtualSize
;
270 sec
->PointerToRawData
= (BYTE
*)xcnlnk
- addr
;
271 sec
->Characteristics
= (IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_READ
);
274 *(const char**)xcnlnk
= argv0
;
277 /* Build the resource directory */
281 BUILTIN32_RESOURCE
*rsrc
= descr
->rsrc
;
282 IMAGE_RESOURCE_DATA_ENTRY
*rdep
;
283 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_RESOURCE_DIRECTORY
];
284 dir
->VirtualAddress
= (BYTE
*)rsrc
->restab
- addr
;
285 dir
->Size
= rsrc
->restabsize
;
286 rdep
= rsrc
->entries
;
287 for (i
= 0; i
< rsrc
->nresources
; i
++) rdep
[i
].OffsetToData
+= dir
->VirtualAddress
;
290 /* Build the export directory */
294 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_EXPORT_DIRECTORY
];
295 dir
->VirtualAddress
= (BYTE
*)exports
- addr
;
296 dir
->Size
= descr
->exports_size
;
298 fixup_rva_ptrs( (void *)exports
->AddressOfFunctions
, addr
, exports
->NumberOfFunctions
);
299 fixup_rva_ptrs( (void *)exports
->AddressOfNames
, addr
, exports
->NumberOfNames
);
300 fixup_rva_ptrs( &exports
->Name
, addr
, 1 );
301 fixup_rva_ptrs( &exports
->AddressOfFunctions
, addr
, 1 );
302 fixup_rva_ptrs( &exports
->AddressOfNames
, addr
, 1 );
303 fixup_rva_ptrs( &exports
->AddressOfNameOrdinals
, addr
, 1 );
305 /* Setup relay debugging entry points */
306 if (WARN_ON(relay
) || TRACE_ON(relay
)) RELAY_SetupDLL( addr
);
309 return (HMODULE
)addr
;
312 /***********************************************************************
313 * BUILTIN32_LoadLibraryExA
315 * Partly copied from the original PE_ version.
318 WINE_MODREF
*BUILTIN32_LoadLibraryExA(LPCSTR path
, DWORD flags
)
320 struct load_dll_request
*req
= get_req_buffer();
324 char dllname
[MAX_PATH
], *p
;
328 /* Fix the name in case we have a full path and extension */
329 if ((p
= strrchr( path
, '\\' ))) path
= p
+ 1;
330 lstrcpynA( dllname
, path
, sizeof(dllname
) );
332 p
= strrchr( dllname
, '.' );
333 if (!p
) strcat( dllname
, ".dll" );
335 /* Search built-in descriptor */
336 for (i
= 0; i
< nb_dlls
; i
++)
337 if (!strcasecmp( builtin_dlls
[i
]->filename
, dllname
)) goto found
;
339 if ((handle
= BUILTIN32_dlopen( dllname
)))
341 for (i
= 0; i
< nb_dlls
; i
++)
342 if (!strcasecmp( builtin_dlls
[i
]->filename
, dllname
)) goto found
;
343 ERR( "loaded .so but dll %s still not found\n", dllname
);
344 BUILTIN32_dlclose( handle
);
347 SetLastError( ERROR_FILE_NOT_FOUND
);
351 /* Load built-in module */
354 if (!(dll_modules
[i
] = BUILTIN32_DoLoadImage( builtin_dlls
[i
] ))) return NULL
;
356 else BUILTIN32_WarnSecondInstance( builtin_dlls
[i
]->filename
);
358 /* Create 16-bit dummy module */
359 if ((hModule16
= MODULE_CreateDummyModule( dllname
, dll_modules
[i
] )) < 32)
361 SetLastError( (DWORD
)hModule16
);
362 return NULL
; /* FIXME: Should unload the builtin module */
364 pModule
= (NE_MODULE
*)GlobalLock16( hModule16
);
365 pModule
->flags
= NE_FFLAGS_LIBMODULE
| NE_FFLAGS_SINGLEDATA
| NE_FFLAGS_WIN32
| NE_FFLAGS_BUILTIN
;
367 /* Create 32-bit MODREF */
368 if ( !(wm
= PE_CreateModule( pModule
->module32
, dllname
, flags
, TRUE
)) )
370 ERR( "can't load %s\n", path
);
371 FreeLibrary16( hModule16
); /* FIXME: Should unload the builtin module */
372 SetLastError( ERROR_OUTOFMEMORY
);
376 if (wm
->binfmt
.pe
.pe_export
)
377 SNOOP_RegisterDLL(wm
->module
,wm
->modname
,wm
->binfmt
.pe
.pe_export
->NumberOfFunctions
);
380 req
->base
= (void *)pModule
->module32
;
383 req
->name
= &wm
->modname
;
384 server_call_noerr( REQ_LOAD_DLL
);
388 /***********************************************************************
389 * BUILTIN32_LoadExeModule
391 HMODULE
BUILTIN32_LoadExeModule( LPCSTR
*filename
)
395 /* Search built-in EXE descriptor */
396 for ( i
= 0; i
< nb_dlls
; i
++ )
397 if ( !(builtin_dlls
[i
]->characteristics
& IMAGE_FILE_DLL
) )
401 MESSAGE( "More than one built-in EXE module loaded!\n" );
410 MESSAGE( "No built-in EXE module loaded! Did you create a .spec file?\n" );
414 /* Load built-in module */
415 if ( !dll_modules
[exe
] )
416 if ( !(dll_modules
[exe
] = BUILTIN32_DoLoadImage( builtin_dlls
[exe
] )) )
419 *filename
= builtin_dlls
[exe
]->filename
;
420 return dll_modules
[exe
];
424 /***********************************************************************
425 * BUILTIN32_UnloadLibrary
427 * Unload the built-in library and free the modref.
429 void BUILTIN32_UnloadLibrary(WINE_MODREF
*wm
)
431 /* FIXME: do something here */
434 /***********************************************************************
435 * BUILTIN32_RegisterDLL
437 * Register a built-in DLL descriptor.
439 void BUILTIN32_RegisterDLL( const BUILTIN32_DESCRIPTOR
*descr
)
441 assert( nb_dlls
< MAX_DLLS
);
442 builtin_dlls
[nb_dlls
++] = descr
;
445 /***********************************************************************
446 * BUILTIN32_Unimplemented
448 * This function is called for unimplemented 32-bit entry points (declared
449 * as 'stub' in the spec file).
451 void BUILTIN32_Unimplemented( const char *dllname
, const char *funcname
)
453 __RESTORE_ES
; /* Just in case */
455 MESSAGE( "No handler for Win32 routine %s.%s", dllname
, funcname
);
457 MESSAGE( " (called from %p)", __builtin_return_address(1) );