Sat Aug 8 19:11:46 1998 Marcus Meissner <marcus@jet.franken.de> * [*/*] Added some missing WINAPI and some missing prototypes for functions. * [controls/static.c] Got rid of the MODULE32_LookupHMODULE error showing up for every message box. * [windows/winproc.c] WM_NOTIFY 16->32 mapping (AOL Instant Messenger or however it is called). * [misc/winsock.c] hostent/servent/protoent should not use the same static buffers. (has broken nt3.15 finger.exe which does hp=gethostbyname(), then getservbyname("finger","tcp") and the references hp->h_addr_list[0]). Sat Aug 8 13:21:24 1998 Alexandre Julliard <julliard@lrc.epfl.ch> * [include/server.h] [tools/make_requests] [server/request.c] [server/trace.c] Automated part of the client/server request code generation. Added tracing of client/server communication. * [scheduler/*.c] [server/process.c] Added support for server-side handles. * [scheduler/thread.c] Added DLL_THREAD_ATTACH/DETACH notifications. * [configure.in] Added check for -lsocket. * [windows/winproc.c] Return the thunk address in WINPROC_GetProc if the function types don't match. Sat Aug 8 02:44:04 1998 Douglas Ridgway <ridgway@winehq.com> * [windows/winproc.c][windows/win.c][windows/message.c] Documentation for CallWindowProc, SetWindowLong, DispatchMessage, WaitMessage, GetMessage, and PeekMessage. Sat Aug 8 01:00:00 1998 Juergen Schmied <juergen.schmied@metronet.de> * [controls/commctrl.c][controls/widgets.c][include/builtin32.h] [include/commctrl.h][relay32/builtin32.c][relay32/comctl32.spec] [tools/build.c] [relay32/shell32.spec] Added the functionality of the LibMain function. The common controls are properly initialized now. * [controls/treeview.c][memory/atom.c][scheduler/thread.c][windows/class.c] [windows/msgbox.c][windows/win.c] Put TRACE in, put SetLastError() in. * [include/interfaces.h] Added IClassFactory::LockServer. * [include/ole2.h] Added struct for LPOLEMENUGROUPWIDTHS32, HOLEMENU32. * [include/shell.h][include/shlobj.h][misc/shell.c][ole/folders.c] Reorganized and many structs and classes (IShellBrowser,IShellView) added. shell32.dll should work in many cases now. Started SHGetFileInfoA implementeation, rewrote SHGetPathFromIDList32A. New Shell32LibMain started ShellIconCache Implementation. * [misc/shellord.c] Rewrote ILCombine, ILGetSize New stubs SHFind_InitMenuPopup, FileMenu_Create, ShellExecuteEx, SHSetInstanceExplorer, SHGetInstanceExplorer, SHFreeUnusedLibraries. * [include/winerror.h] Class and window related error codes added. * [memory/heap.c] Changed lstrlen32A to strlen to get rid of milions of TRACE lines. * [misc/ddeml.c] First lines for DdeCreateStringHandle32A / DdeFreeStringHandle32. * [misc/network.c][relay32/mpr.spec] Fixed some bugs, changed ordinals. * [windows/class.c] Workarounds for incorrect hInstance handling. Fixes parts of MSWord95/Excel95 and Money95. Thu Aug 6 21:05:35 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de> * [windows/nonclient.c][misc/tweak.c][include/tweak.h] [documentation/win95look] Removed some tweak variables. They are no longer needed. * [files/dos_fs.c] Added check for null pointer in DOSFS_GetDevice(). * [controls/tooltips.c][include/commctrl.h] Improved tooltips. * [controls/status.c][include/commctrl.h] Cleaned up code and added tooltip support. * [controls/toolbar.c][include/commctrl.h] Added tooltip support. * [documentation/common_controls] Updated. Thu Aug 6 00:05:22 1998 Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de> * [include/ver.h] [misc/ver.c] Write VIF_BUFFTOOSMALL, not VIF_BUFTOSMALL. * [debugger/hash.c] [debugger/stabs.c] Make debug output more friendly for posting. * [files/file.c] Partial implementation of OF_SHARE_EXCLUSIVE. Needed for Quicklogic/QuickChip (InstallShield). * [files/profile.c] When a cached-only entry is found, return it. * [graphics/x11drv/xfont.c] Accept a space as delimiter for a fontname and inhibit overrun (Make xplasim.ex from the Phillips Coolrunner CPLD suite proceed). * [miscemu/main.c] Delay setting IF1632_CallLargeStack after loading the executables. Stops fpgaexp.exe from the Viewlogic FPGA suite from crashing when showing the Blinker error Message Box. * [misc/network.c] Make WNetGetConnection16 recognise a CDROM as a local drive. * [multimedia/mmsystem.c] Preliminary check for MCI_ALL_DEVICE_ID in MCI_Close by a FIXME. Tue Aug 4 21:15:23 1998 James Juran <jrj120@psu.edu> * [ole/ole2nls.c] Fixed bug in CompareString32A. strcmp() doesn't necessarily return -1, 0, or 1, which the previous code depended on. Changed name of is_punctuation to OLE2NLS_isPunctuation. Made NORM_IGNOREWIDTH not print a FIXME message in LCMapString32A. Other debugging messages, documentation, and code cleanups. * [objects/font.c] [relay32/gdi32.spec] [include/winerror.h] Added stub for GetFontData32, and added GDI_ERROR constant to winerror.h. Tue Aug 4 07:44:43 1998 Ove Kaaven <ovek@arcticnet.no> * [multimedia/mmio.c] Implemented mmioSetBuffer, mmioAdvance, mmioAscend, and mmioCreateChunk to the best of my knowledge. But watch out, there's bound to be bugs in there... * [include/mmsystem.h] [multimedia/mmsystem.c] Hacked in support for 32-bit multimedia function callbacks. * [AUTHORS] [misc/shell.c] Selfishly credited my authorship. Hopefully I'm excused. * [include/dosexe.h] [include/module.h] [loader/dos/*] [loader/module.c] [loader/task.c] [Makefile.in] [configure.in] [Makefile.in] Added DOS EXE (MZ) loader and virtual machine. Task structure integration thanks to Ulrich Weigand. * [files/dos_fs.c] Work around a null pointer dereference if ioctlGetDeviceInfo-ing a FILE_DupUnixHandle'd file (i.e. GetStdHandle'd). * [include/miscemu.h] [include/winnt.h] [loader/main.c] [memory/global.c] [msdos/dpmi.c] [msdos/dosmem.c] Added support for DOS memory images, and added DOSMEM_ResizeBlock() and DOSMEM_Available(). * [msdos/int21.c] Added support for the DOS virtual machine, tweaked handle assignment to avoid stdio clashes, forced INT21_FindNext to exit wildcardless searches after finding one entry, added AH=7, 8, 9, C, 48, 49, 4A, and 7160 CL=1 (Get Short Filename), and made the long filename calls only respond if running with with -winver win95. * [objects/cursoricon.c] DestroyCursor32 and DestroyIcon32 should now free the objects (hopefully) correctly. Sun Aug 2 21:42:09 1998 Huw D M Davies <daviesh@abacus.physics.ox.ac.uk> * [graphics/psdrv/*] [include/psdrv.h] Added PPD file parsing - at the moment it reads a file called default.ppd from the directory in which you start Wine. Page sizes other than A4 should now work (landscape may not). All fonts that are present on your printer (according to the PPD) should be available, providing you have the AFM files. Fonts should now be the correct size. Graphics is still basically lines only. See graphics/psdrv/README . * [misc/printdrv.c] Yet more Drv[Get/Set]PrinterData fixes. Fri Jul 31 21:33:22 1998 Per Lindström <pelinstr@algonet.se> * [relay32/crtdll.spec] [misc/crtdll.c] Added stub for freopen, _findfirst, _findnext, _fstat and _read. * [files/directory.c] Modified warning message. Wed Jul 29 11:25:28 1998 Luiz Otavio L. Zorzella <zorzella@nr.conexware.com> * [objects/font.c] Added stub for GetFontData. * [multimedia/msvideo.c] Created this file to hold the msvideo.dll calls (and maybe also msvfw32.dll). * [objects/cursoricon.c] Added search in Global Heap for cursor when trying to destroy it with DestroyCursor16. This test should be done in many (all?) other functions that use FreeResource. * [controls/treeview.c] [include/commctrl.h] Minor correction in name and addition of many placeholders for TVM messages in TREEVIEW_WindowProc. * [msdos/dpmi.c] Fixed a bug in DPMI_xrealloc where in a copy of a memory region "A" of size "a" to a region "B" of size "b", "b" bytes were being copied, instead of "a", as the new version does. This both increases speed, as well as avoids segfaults.
1011 lines
32 KiB
C
1011 lines
32 KiB
C
/*
|
|
* Copyright 1994 Eric Youndale & Erik Bos
|
|
* Copyright 1995 Martin von Löwis
|
|
* Copyright 1996-98 Marcus Meissner
|
|
*
|
|
* based on Eric Youndale's pe-test and:
|
|
*
|
|
* ftp.microsoft.com:/pub/developer/MSDN/CD8/PEFILE.ZIP
|
|
* make that:
|
|
* ftp.microsoft.com:/developr/MSDN/OctCD/PEFILE.ZIP
|
|
*/
|
|
/* Notes:
|
|
* Before you start changing something in this file be aware of the following:
|
|
*
|
|
* - There are several functions called recursively. In a very subtle and
|
|
* obscure way. DLLs can reference each other recursively etc.
|
|
* - If you want to enhance, speed up or clean up something in here, think
|
|
* twice WHY it is implemented in that strange way. There is usually a reason.
|
|
* Though sometimes it might just be lazyness ;)
|
|
* - In PE_MapImage, right before fixup_imports() all external and internal
|
|
* state MUST be correct since this function can be called with the SAME image
|
|
* AGAIN. (Thats recursion for you.) That means MODREF.module and
|
|
* NE_MODULE.module32.
|
|
* - No, you (usually) cannot use Linux mmap() to mmap() the images directly.
|
|
*
|
|
* The problem is, that there is not direct 1:1 mapping from a diskimage and
|
|
* a memoryimage. The headers at the start are mapped linear, but the sections
|
|
* are not. For x86 the sections are 512 byte aligned in file and 4096 byte
|
|
* aligned in memory. Linux likes them 4096 byte aligned in memory (due to
|
|
* x86 pagesize, this cannot be fixed without a rather large kernel rewrite)
|
|
* and 'blocksize' file-aligned (offsets). Since we have 512/1024/2048 (CDROM)
|
|
* and other byte blocksizes, we can't do this. However, this could be less
|
|
* difficult to support... (See mm/filemap.c).
|
|
* - All those function map things into a new addresspace. From the wrong
|
|
* process and the wrong thread. So calling other API functions will mess
|
|
* things up badly sometimes.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/mman.h>
|
|
#include "windows.h"
|
|
#include "winbase.h"
|
|
#include "callback.h"
|
|
#include "file.h"
|
|
#include "heap.h"
|
|
#include "neexe.h"
|
|
#include "peexe.h"
|
|
#include "process.h"
|
|
#include "thread.h"
|
|
#include "pe_image.h"
|
|
#include "module.h"
|
|
#include "global.h"
|
|
#include "task.h"
|
|
#include "snoop.h"
|
|
#include "debug.h"
|
|
|
|
static void PE_InitDLL(WINE_MODREF *wm, DWORD type, LPVOID lpReserved);
|
|
|
|
/* convert PE image VirtualAddress to Real Address */
|
|
#define RVA(x) ((unsigned int)load_addr+(unsigned int)(x))
|
|
|
|
#define AdjustPtr(ptr,delta) ((char *)(ptr) + (delta))
|
|
|
|
void dump_exports( HMODULE32 hModule )
|
|
{
|
|
char *Module;
|
|
int i, j;
|
|
u_short *ordinal;
|
|
u_long *function,*functions;
|
|
u_char **name;
|
|
unsigned int load_addr = hModule;
|
|
|
|
DWORD rva_start = PE_HEADER(hModule)->OptionalHeader
|
|
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
|
DWORD rva_end = rva_start + PE_HEADER(hModule)->OptionalHeader
|
|
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
|
|
IMAGE_EXPORT_DIRECTORY *pe_exports = (IMAGE_EXPORT_DIRECTORY*)RVA(rva_start);
|
|
|
|
Module = (char*)RVA(pe_exports->Name);
|
|
TRACE(win32,"*******EXPORT DATA*******\n");
|
|
TRACE(win32,"Module name is %s, %ld functions, %ld names\n",
|
|
Module, pe_exports->NumberOfFunctions, pe_exports->NumberOfNames);
|
|
|
|
ordinal=(u_short*) RVA(pe_exports->AddressOfNameOrdinals);
|
|
functions=function=(u_long*) RVA(pe_exports->AddressOfFunctions);
|
|
name=(u_char**) RVA(pe_exports->AddressOfNames);
|
|
|
|
TRACE(win32," Ord RVA Addr Name\n" );
|
|
for (i=0;i<pe_exports->NumberOfFunctions;i++, function++)
|
|
{
|
|
if (!*function) continue; /* No such function */
|
|
if (TRACE_ON(win32)){
|
|
dbg_decl_str(win32, 1024);
|
|
|
|
dsprintf(win32,"%4ld %08lx %08x",
|
|
i + pe_exports->Base, *function, RVA(*function) );
|
|
/* Check if we have a name for it */
|
|
for (j = 0; j < pe_exports->NumberOfNames; j++)
|
|
if (ordinal[j] == i)
|
|
dsprintf(win32, " %s", (char*)RVA(name[j]) );
|
|
if ((*function >= rva_start) && (*function <= rva_end))
|
|
dsprintf(win32, " (forwarded -> %s)", (char *)RVA(*function));
|
|
TRACE(win32,"%s\n", dbg_str(win32));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Look up the specified function or ordinal in the exportlist:
|
|
* If it is a string:
|
|
* - look up the name in the Name list.
|
|
* - look up the ordinal with that index.
|
|
* - use the ordinal as offset into the functionlist
|
|
* If it is a ordinal:
|
|
* - use ordinal-pe_export->Base as offset into the functionlist
|
|
*/
|
|
FARPROC32 PE_FindExportedFunction(
|
|
PDB32 *process, /* [in] process context */
|
|
WINE_MODREF *wm, /* [in] WINE modreference */
|
|
LPCSTR funcName ) /* [in] function name */
|
|
{
|
|
u_short * ordinal;
|
|
u_long * function;
|
|
u_char ** name, *ename;
|
|
int i;
|
|
PE_MODREF *pem = &(wm->binfmt.pe);
|
|
IMAGE_EXPORT_DIRECTORY *exports = pem->pe_export;
|
|
unsigned int load_addr = wm->module;
|
|
u_long rva_start, rva_end, addr;
|
|
char * forward;
|
|
|
|
if (HIWORD(funcName))
|
|
TRACE(win32,"(%s)\n",funcName);
|
|
else
|
|
TRACE(win32,"(%d)\n",(int)funcName);
|
|
if (!exports) {
|
|
/* Not a fatal problem, some apps do
|
|
* GetProcAddress(0,"RegisterPenApp") which triggers this
|
|
* case.
|
|
*/
|
|
WARN(win32,"Module %08x(%s)/MODREF %p doesn't have a exports table.\n",wm->module,wm->modname,pem);
|
|
return NULL;
|
|
}
|
|
ordinal = (u_short*) RVA(exports->AddressOfNameOrdinals);
|
|
function= (u_long*) RVA(exports->AddressOfFunctions);
|
|
name = (u_char **) RVA(exports->AddressOfNames);
|
|
forward = NULL;
|
|
rva_start = PE_HEADER(wm->module)->OptionalHeader
|
|
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
|
rva_end = rva_start + PE_HEADER(wm->module)->OptionalHeader
|
|
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
|
|
|
|
if (HIWORD(funcName)) {
|
|
for(i=0; i<exports->NumberOfNames; i++) {
|
|
ename=(char*)RVA(*name);
|
|
if(!strcmp(ename,funcName))
|
|
{
|
|
addr = function[*ordinal];
|
|
if (!addr) return NULL;
|
|
if ((addr < rva_start) || (addr >= rva_end))
|
|
return SNOOP_GetProcAddress32(wm->module,ename,*ordinal,(FARPROC32)RVA(addr));
|
|
forward = (char *)RVA(addr);
|
|
break;
|
|
}
|
|
ordinal++;
|
|
name++;
|
|
}
|
|
} else {
|
|
int i;
|
|
if (LOWORD(funcName)-exports->Base > exports->NumberOfFunctions) {
|
|
TRACE(win32," ordinal %d out of range!\n",
|
|
LOWORD(funcName));
|
|
return NULL;
|
|
}
|
|
addr = function[(int)funcName-exports->Base];
|
|
if (!addr) return NULL;
|
|
ename = "";
|
|
if (name) {
|
|
for (i=0;i<exports->NumberOfNames;i++) {
|
|
ename = (char*)RVA(*name);
|
|
if (*ordinal == LOWORD(funcName)-exports->Base)
|
|
break;
|
|
ordinal++;
|
|
name++;
|
|
}
|
|
if (i==exports->NumberOfNames)
|
|
ename = "";
|
|
}
|
|
if ((addr < rva_start) || (addr >= rva_end))
|
|
return SNOOP_GetProcAddress32(wm->module,ename,(DWORD)funcName-exports->Base,(FARPROC32)RVA(addr));
|
|
forward = (char *)RVA(addr);
|
|
}
|
|
if (forward)
|
|
{
|
|
HMODULE32 hMod;
|
|
char module[256];
|
|
char *end = strchr(forward, '.');
|
|
|
|
if (!end) return NULL;
|
|
assert(end-forward<256);
|
|
strncpy(module, forward, (end - forward));
|
|
module[end-forward] = 0;
|
|
hMod = MODULE_FindModule32(process,module);
|
|
assert(hMod);
|
|
return MODULE_GetProcAddress32( process, hMod, end + 1);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
DWORD fixup_imports (PDB32 *process,WINE_MODREF *wm)
|
|
{
|
|
IMAGE_IMPORT_DESCRIPTOR *pe_imp;
|
|
WINE_MODREF *xwm;
|
|
PE_MODREF *pem;
|
|
unsigned int load_addr = wm->module;
|
|
int i;
|
|
char *modname;
|
|
|
|
assert(wm->type==MODULE32_PE);
|
|
pem = &(wm->binfmt.pe);
|
|
if (pem->pe_export)
|
|
modname = (char*) RVA(pem->pe_export->Name);
|
|
else
|
|
modname = "<unknown>";
|
|
|
|
/* OK, now dump the import list */
|
|
TRACE(win32, "Dumping imports list\n");
|
|
|
|
/* first, count the number of imported non-internal modules */
|
|
pe_imp = pem->pe_import;
|
|
if (!pe_imp)
|
|
ERR(win32, "no import directory????\n");
|
|
|
|
/* FIXME: should terminate on 0 Characteristics */
|
|
for (i = 0; pe_imp->Name; pe_imp++)
|
|
i++;
|
|
|
|
/* load the imported modules. They are automatically
|
|
* added to the modref list of the process.
|
|
*/
|
|
|
|
/* FIXME: should terminate on 0 Characteristics */
|
|
for (i = 0, pe_imp = pem->pe_import; pe_imp->Name; pe_imp++) {
|
|
HMODULE32 hImpModule;
|
|
WINE_MODREF **ywm;
|
|
IMAGE_IMPORT_BY_NAME *pe_name;
|
|
LPIMAGE_THUNK_DATA import_list,thunk_list;
|
|
char *name = (char *) RVA(pe_imp->Name);
|
|
|
|
/* don't use MODULE_Load, Win32 creates new task differently */
|
|
hImpModule = PE_LoadLibraryEx32A( name, process, 0, 0 );
|
|
if (!hImpModule) {
|
|
char *p,buffer[2000];
|
|
|
|
/* GetModuleFileName would use the wrong process, so don't use it */
|
|
strcpy(buffer,wm->shortname);
|
|
if (!(p = strrchr (buffer, '\\')))
|
|
p = buffer;
|
|
strcpy (p + 1, name);
|
|
hImpModule = PE_LoadLibraryEx32A( buffer, process, 0, 0 );
|
|
}
|
|
if (!hImpModule) {
|
|
ERR (module, "Module %s not found\n", name);
|
|
return 1;
|
|
}
|
|
xwm = wm->next;
|
|
while (xwm) {
|
|
if (xwm->module == hImpModule)
|
|
break;
|
|
xwm = xwm->next;
|
|
}
|
|
if (xwm) {
|
|
/* It has been loaded *BEFORE* us, so we have to initialize
|
|
* it before us. We cannot just link in the xwm before wm,
|
|
* since xwm might reference more dlls which would be in the
|
|
* wrong order after that.
|
|
* Instead we link in wm right AFTER xwm, which should keep
|
|
* the correct order. (I am not 100% sure about that.)
|
|
*/
|
|
/* unlink wm from chain */
|
|
ywm = &(process->modref_list);
|
|
while (*ywm) {
|
|
if ((*ywm)==wm)
|
|
break;
|
|
ywm = &((*ywm)->next);
|
|
}
|
|
*ywm = wm->next;
|
|
|
|
/* link wm directly AFTER xwm */
|
|
wm->next = xwm->next;
|
|
xwm->next = wm;
|
|
|
|
}
|
|
i++;
|
|
|
|
/* FIXME: forwarder entries ... */
|
|
|
|
if (pe_imp->u.OriginalFirstThunk != 0) { /* original MS style */
|
|
TRACE(win32, "Microsoft style imports used\n");
|
|
import_list =(LPIMAGE_THUNK_DATA) RVA(pe_imp->u.OriginalFirstThunk);
|
|
thunk_list = (LPIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk);
|
|
|
|
while (import_list->u1.Ordinal) {
|
|
if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal)) {
|
|
int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
|
|
|
|
TRACE(win32, "--- Ordinal %s,%d\n", name, ordinal);
|
|
thunk_list->u1.Function=MODULE_GetProcAddress32(
|
|
process, hImpModule, (LPCSTR)ordinal
|
|
);
|
|
if (!thunk_list->u1.Function) {
|
|
ERR(win32,"No implementation for %s.%d, setting to 0xdeadbeef\n",
|
|
name, ordinal);
|
|
thunk_list->u1.Function = (FARPROC32)0xdeadbeef;
|
|
}
|
|
} else { /* import by name */
|
|
pe_name = (LPIMAGE_IMPORT_BY_NAME)RVA(import_list->u1.AddressOfData);
|
|
TRACE(win32, "--- %s %s.%d\n", pe_name->Name, name, pe_name->Hint);
|
|
thunk_list->u1.Function=MODULE_GetProcAddress32(
|
|
process, hImpModule, pe_name->Name
|
|
);
|
|
if (!thunk_list->u1.Function) {
|
|
ERR(win32,"No implementation for %s.%d(%s), setting to 0xdeadbeef\n",
|
|
name,pe_name->Hint,pe_name->Name);
|
|
thunk_list->u1.Function = (FARPROC32)0xdeadbeef;
|
|
}
|
|
}
|
|
import_list++;
|
|
thunk_list++;
|
|
}
|
|
} else { /* Borland style */
|
|
TRACE(win32, "Borland style imports used\n");
|
|
thunk_list = (LPIMAGE_THUNK_DATA) RVA(pe_imp->FirstThunk);
|
|
while (thunk_list->u1.Ordinal) {
|
|
if (IMAGE_SNAP_BY_ORDINAL(thunk_list->u1.Ordinal)) {
|
|
/* not sure about this branch, but it seems to work */
|
|
int ordinal = IMAGE_ORDINAL(thunk_list->u1.Ordinal);
|
|
|
|
TRACE(win32,"--- Ordinal %s.%d\n",name,ordinal);
|
|
thunk_list->u1.Function=MODULE_GetProcAddress32(
|
|
process, hImpModule, (LPCSTR) ordinal
|
|
);
|
|
if (!thunk_list->u1.Function) {
|
|
ERR(win32, "No implementation for %s.%d, setting to 0xdeadbeef\n",
|
|
name,ordinal);
|
|
thunk_list->u1.Function = (FARPROC32)0xdeadbeef;
|
|
}
|
|
} else {
|
|
pe_name=(LPIMAGE_IMPORT_BY_NAME) RVA(thunk_list->u1.AddressOfData);
|
|
TRACE(win32,"--- %s %s.%d\n",
|
|
pe_name->Name,name,pe_name->Hint);
|
|
thunk_list->u1.Function=MODULE_GetProcAddress32(
|
|
process, hImpModule, pe_name->Name
|
|
);
|
|
if (!thunk_list->u1.Function) {
|
|
ERR(win32, "No implementation for %s.%d, setting to 0xdeadbeef\n",
|
|
name, pe_name->Hint);
|
|
thunk_list->u1.Function = (FARPROC32)0xdeadbeef;
|
|
}
|
|
}
|
|
thunk_list++;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int calc_vma_size( HMODULE32 hModule )
|
|
{
|
|
int i,vma_size = 0;
|
|
IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(hModule);
|
|
|
|
TRACE(win32, "Dump of segment table\n");
|
|
TRACE(win32, " Name VSz Vaddr SzRaw Fileadr *Reloc *Lineum #Reloc #Linum Char\n");
|
|
for (i = 0; i< PE_HEADER(hModule)->FileHeader.NumberOfSections; i++)
|
|
{
|
|
TRACE(win32, "%8s: %4.4lx %8.8lx %8.8lx %8.8lx %8.8lx %8.8lx %4.4x %4.4x %8.8lx\n",
|
|
pe_seg->Name,
|
|
pe_seg->Misc.VirtualSize,
|
|
pe_seg->VirtualAddress,
|
|
pe_seg->SizeOfRawData,
|
|
pe_seg->PointerToRawData,
|
|
pe_seg->PointerToRelocations,
|
|
pe_seg->PointerToLinenumbers,
|
|
pe_seg->NumberOfRelocations,
|
|
pe_seg->NumberOfLinenumbers,
|
|
pe_seg->Characteristics);
|
|
vma_size = MAX(vma_size, pe_seg->VirtualAddress+pe_seg->SizeOfRawData);
|
|
pe_seg++;
|
|
}
|
|
return vma_size;
|
|
}
|
|
|
|
static void do_relocations(WINE_MODREF *wm)
|
|
{
|
|
PE_MODREF *pem = &(wm->binfmt.pe);
|
|
int delta = wm->module - PE_HEADER(wm->module)->OptionalHeader.ImageBase;
|
|
unsigned int load_addr= wm->module;
|
|
|
|
IMAGE_BASE_RELOCATION *r = pem->pe_reloc;
|
|
int hdelta = (delta >> 16) & 0xFFFF;
|
|
int ldelta = delta & 0xFFFF;
|
|
|
|
/* int reloc_size = */
|
|
|
|
if(delta == 0)
|
|
/* Nothing to do */
|
|
return;
|
|
while(r->VirtualAddress)
|
|
{
|
|
char *page = (char*) RVA(r->VirtualAddress);
|
|
int count = (r->SizeOfBlock - 8)/2;
|
|
int i;
|
|
TRACE(fixup, "%x relocations for page %lx\n",
|
|
count, r->VirtualAddress);
|
|
/* patching in reverse order */
|
|
for(i=0;i<count;i++)
|
|
{
|
|
int offset = r->TypeOffset[i] & 0xFFF;
|
|
int type = r->TypeOffset[i] >> 12;
|
|
TRACE(fixup,"patching %x type %x\n", offset, type);
|
|
switch(type)
|
|
{
|
|
case IMAGE_REL_BASED_ABSOLUTE: break;
|
|
case IMAGE_REL_BASED_HIGH:
|
|
*(short*)(page+offset) += hdelta;
|
|
break;
|
|
case IMAGE_REL_BASED_LOW:
|
|
*(short*)(page+offset) += ldelta;
|
|
break;
|
|
case IMAGE_REL_BASED_HIGHLOW:
|
|
#if 1
|
|
*(int*)(page+offset) += delta;
|
|
#else
|
|
{ int h=*(unsigned short*)(page+offset);
|
|
int l=r->TypeOffset[++i];
|
|
*(unsigned int*)(page + offset) = (h<<16) + l + delta;
|
|
}
|
|
#endif
|
|
break;
|
|
case IMAGE_REL_BASED_HIGHADJ:
|
|
WARN(win32, "Don't know what to do with IMAGE_REL_BASED_HIGHADJ\n");
|
|
break;
|
|
case IMAGE_REL_BASED_MIPS_JMPADDR:
|
|
WARN(win32, "Is this a MIPS machine ???\n");
|
|
break;
|
|
default:
|
|
WARN(win32, "Unknown fixup type\n");
|
|
break;
|
|
}
|
|
}
|
|
r = (IMAGE_BASE_RELOCATION*)((char*)r + r->SizeOfBlock);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
* PE_LoadImage
|
|
* Load one PE format DLL/EXE into memory
|
|
*
|
|
* Unluckily we can't just mmap the sections where we want them, for
|
|
* (at least) Linux does only support offsets which are page-aligned.
|
|
*
|
|
* BUT we have to map the whole image anyway, for Win32 programs sometimes
|
|
* want to access them. (HMODULE32 point to the start of it)
|
|
*/
|
|
static HMODULE32 PE_LoadImage( HFILE32 hFile )
|
|
{
|
|
HMODULE32 hModule;
|
|
HANDLE32 mapping;
|
|
|
|
/* map the PE file somewhere */
|
|
mapping = CreateFileMapping32A( hFile, NULL, PAGE_READONLY | SEC_COMMIT,
|
|
0, 0, NULL );
|
|
if (!mapping)
|
|
{
|
|
WARN( win32, "CreateFileMapping error %ld\n",
|
|
GetLastError() );
|
|
return 0;
|
|
}
|
|
hModule = (HMODULE32)MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
|
|
CloseHandle( mapping );
|
|
if (!hModule)
|
|
{
|
|
WARN( win32, "PE_LoadImage: MapViewOfFile error %ld\n",
|
|
GetLastError() );
|
|
return 0;
|
|
}
|
|
|
|
if (PE_HEADER(hModule)->Signature != IMAGE_NT_SIGNATURE)
|
|
{
|
|
WARN(win32,"image doesn't have PE signature, but 0x%08lx\n",
|
|
PE_HEADER(hModule)->Signature );
|
|
goto error;
|
|
}
|
|
|
|
if (PE_HEADER(hModule)->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
|
|
{
|
|
MSG("Trying to load PE image for unsupported architecture (");
|
|
switch (PE_HEADER(hModule)->FileHeader.Machine)
|
|
{
|
|
case IMAGE_FILE_MACHINE_UNKNOWN: MSG("Unknown\n"); break;
|
|
case IMAGE_FILE_MACHINE_I860: MSG("I860\n"); break;
|
|
case IMAGE_FILE_MACHINE_R3000: MSG("R3000\n"); break;
|
|
case IMAGE_FILE_MACHINE_R4000: MSG("R4000\n"); break;
|
|
case IMAGE_FILE_MACHINE_R10000: MSG("R10000\n"); break;
|
|
case IMAGE_FILE_MACHINE_ALPHA: MSG("Alpha\n"); break;
|
|
case IMAGE_FILE_MACHINE_POWERPC: MSG("PowerPC\n"); break;
|
|
default: MSG("Unknown-%04x\n",
|
|
PE_HEADER(hModule)->FileHeader.Machine); break;
|
|
}
|
|
goto error;
|
|
}
|
|
return hModule;
|
|
|
|
error:
|
|
UnmapViewOfFile( (LPVOID)hModule );
|
|
return 0;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* This maps a loaded PE dll into the address space of the specified process.
|
|
*/
|
|
static BOOL32 PE_MapImage( PDB32 *process,WINE_MODREF *wm, OFSTRUCT *ofs, DWORD flags )
|
|
{
|
|
PE_MODREF *pem;
|
|
int i, result;
|
|
DWORD load_addr;
|
|
IMAGE_DATA_DIRECTORY dir;
|
|
char *modname;
|
|
int vma_size;
|
|
HMODULE32 hModule = wm->module;
|
|
|
|
IMAGE_SECTION_HEADER *pe_seg;
|
|
IMAGE_DOS_HEADER *dos_header = (IMAGE_DOS_HEADER *)hModule;
|
|
IMAGE_NT_HEADERS *nt_header = PE_HEADER(hModule);
|
|
|
|
pem = &(wm->binfmt.pe);
|
|
|
|
result = GetLongPathName32A(ofs->szPathName,NULL,0);
|
|
wm->longname = (char*)HeapAlloc(process->heap,0,result+1);
|
|
GetLongPathName32A(ofs->szPathName,wm->longname,result+1);
|
|
|
|
wm->shortname = HEAP_strdupA(process->heap,0,ofs->szPathName);
|
|
|
|
if (!(nt_header->FileHeader.Characteristics & IMAGE_FILE_DLL))
|
|
{
|
|
if (process->exe_modref)
|
|
FIXME(win32,"overwriting old exe_modref... arrgh\n");
|
|
process->exe_modref = wm;
|
|
}
|
|
|
|
load_addr = nt_header->OptionalHeader.ImageBase;
|
|
vma_size = calc_vma_size( hModule );
|
|
TRACE(win32, "Load addr is %lx\n",load_addr);
|
|
load_addr = (DWORD)VirtualAlloc( (void*)load_addr, vma_size,
|
|
MEM_RESERVE | MEM_COMMIT,
|
|
PAGE_EXECUTE_READWRITE );
|
|
if (load_addr == 0) {
|
|
load_addr = (DWORD)VirtualAlloc( NULL, vma_size,
|
|
MEM_RESERVE | MEM_COMMIT,
|
|
PAGE_EXECUTE_READWRITE );
|
|
}
|
|
/* NOTE: this changes a value in the process modref chain, which can
|
|
* be accessed independently from this function
|
|
*/
|
|
wm->module = (HMODULE32)load_addr;
|
|
|
|
TRACE(win32, "Load addr is really %lx, range %x\n",
|
|
load_addr, vma_size);
|
|
|
|
TRACE(segment, "Loading %s at %lx, range %x\n",
|
|
ofs->szPathName, load_addr, vma_size );
|
|
|
|
/* Store the NT header at the load addr
|
|
* (FIXME: should really use mmap)
|
|
*/
|
|
*(IMAGE_DOS_HEADER *)load_addr = *dos_header;
|
|
*(IMAGE_NT_HEADERS *)(load_addr + dos_header->e_lfanew) = *nt_header;
|
|
memcpy(PE_SECTIONS(load_addr),PE_SECTIONS(hModule),sizeof(IMAGE_SECTION_HEADER)*nt_header->FileHeader.NumberOfSections);
|
|
|
|
pe_seg = PE_SECTIONS(hModule);
|
|
for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++, pe_seg++)
|
|
{
|
|
/* memcpy only non-BSS segments */
|
|
/* FIXME: this should be done by mmap(..MAP_PRIVATE|MAP_FIXED..)
|
|
* but it is not possible for (at least) Linux needs
|
|
* a page-aligned offset.
|
|
*/
|
|
if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
|
|
memcpy((char*)RVA(pe_seg->VirtualAddress),
|
|
(char*)(hModule + pe_seg->PointerToRawData),
|
|
pe_seg->SizeOfRawData
|
|
);
|
|
|
|
result = RVA (pe_seg->VirtualAddress);
|
|
#if 1
|
|
/* not needed, memory is zero */
|
|
if(strcmp(pe_seg->Name, ".bss") == 0)
|
|
memset((void *)result, 0,
|
|
pe_seg->Misc.VirtualSize ?
|
|
pe_seg->Misc.VirtualSize :
|
|
pe_seg->SizeOfRawData);
|
|
#endif
|
|
|
|
if(strcmp(pe_seg->Name, ".idata") == 0)
|
|
pem->pe_import = (LPIMAGE_IMPORT_DESCRIPTOR) result;
|
|
|
|
if(strcmp(pe_seg->Name, ".edata") == 0)
|
|
pem->pe_export = (LPIMAGE_EXPORT_DIRECTORY) result;
|
|
|
|
if(strcmp(pe_seg->Name, ".rsrc") == 0)
|
|
pem->pe_resource = (LPIMAGE_RESOURCE_DIRECTORY) result;
|
|
|
|
if(strcmp(pe_seg->Name, ".reloc") == 0)
|
|
pem->pe_reloc = (LPIMAGE_BASE_RELOCATION) result;
|
|
}
|
|
|
|
/* There is word that the actual loader does not care about the
|
|
section names, and only goes for the DataDirectory */
|
|
dir=nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
|
if(dir.Size)
|
|
{
|
|
if(pem->pe_export && (int)pem->pe_export!=RVA(dir.VirtualAddress))
|
|
WARN(win32,"wrong export directory??\n");
|
|
/* always trust the directory */
|
|
pem->pe_export = (LPIMAGE_EXPORT_DIRECTORY) RVA(dir.VirtualAddress);
|
|
}
|
|
|
|
dir=nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
|
if(dir.Size)
|
|
{
|
|
/*
|
|
if(pem->pe_import && (int)pem->pe_import!=RVA(dir.VirtualAddress))
|
|
WARN(win32,"wrong import directory??\n");
|
|
*/
|
|
pem->pe_import = (LPIMAGE_IMPORT_DESCRIPTOR) RVA(dir.VirtualAddress);
|
|
}
|
|
|
|
dir=nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
|
|
if(dir.Size)
|
|
{
|
|
if(pem->pe_resource && (int)pem->pe_resource!=RVA(dir.VirtualAddress))
|
|
WARN(win32,"wrong resource directory??\n");
|
|
pem->pe_resource = (LPIMAGE_RESOURCE_DIRECTORY) RVA(dir.VirtualAddress);
|
|
}
|
|
|
|
if(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size)
|
|
FIXME(win32,"Exception directory ignored\n");
|
|
|
|
if(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size)
|
|
FIXME(win32,"Security directory ignored\n");
|
|
|
|
|
|
|
|
dir=nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
|
|
if(dir.Size)
|
|
{
|
|
if(pem->pe_reloc && (int)pem->pe_reloc!= RVA(dir.VirtualAddress))
|
|
WARN(win32,"wrong relocation list??\n");
|
|
pem->pe_reloc = (void *) RVA(dir.VirtualAddress);
|
|
}
|
|
|
|
if(nt_header->OptionalHeader.DataDirectory
|
|
[IMAGE_DIRECTORY_ENTRY_COPYRIGHT].Size)
|
|
FIXME(win32,"Copyright string ignored\n");
|
|
|
|
if(nt_header->OptionalHeader.DataDirectory
|
|
[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size)
|
|
FIXME(win32,"Global Pointer (MIPS) ignored\n");
|
|
|
|
if(nt_header->OptionalHeader.DataDirectory
|
|
[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size)
|
|
FIXME(win32,"Load Configuration directory ignored\n");
|
|
|
|
if(nt_header->OptionalHeader.DataDirectory
|
|
[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size)
|
|
TRACE(win32,"Bound Import directory ignored\n");
|
|
|
|
if(nt_header->OptionalHeader.DataDirectory
|
|
[IMAGE_DIRECTORY_ENTRY_IAT].Size)
|
|
TRACE(win32,"Import Address Table directory ignored\n");
|
|
if(nt_header->OptionalHeader.DataDirectory[13].Size)
|
|
FIXME(win32,"Unknown directory 13 ignored\n");
|
|
if(nt_header->OptionalHeader.DataDirectory[14].Size)
|
|
FIXME(win32,"Unknown directory 14 ignored\n");
|
|
if(nt_header->OptionalHeader.DataDirectory[15].Size)
|
|
FIXME(win32,"Unknown directory 15 ignored\n");
|
|
|
|
if(pem->pe_reloc) do_relocations(wm);
|
|
if(pem->pe_export) {
|
|
dump_exports(wm->module);
|
|
|
|
wm->modname = HEAP_strdupA(process->heap,0,(char*)RVA(pem->pe_export->Name));
|
|
} else {
|
|
/* try to find out the name from the OFSTRUCT */
|
|
char *s;
|
|
modname = s = ofs->szPathName;
|
|
while ((s=strchr(modname,'\\')))
|
|
modname = s+1;
|
|
wm->modname = HEAP_strdupA(process->heap,0,modname);
|
|
}
|
|
if(pem->pe_import) {
|
|
if (fixup_imports(process,wm)) {
|
|
WINE_MODREF **xwm;
|
|
|
|
/* remove entry from modref chain */
|
|
xwm = &(process->modref_list);
|
|
while (*xwm) {
|
|
if (*xwm==wm) {
|
|
*xwm = wm->next;
|
|
break;
|
|
}
|
|
xwm = &((*xwm)->next);
|
|
}
|
|
/* FIXME: there are several more dangling references
|
|
* left. Including dlls loaded by this dll before the
|
|
* failed one. Unrolling is rather difficult with the
|
|
* current structure and we can leave it them lying
|
|
* around with no problems, so we don't care
|
|
*/
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Now that we got everything at the right address,
|
|
* we can unmap the previous module */
|
|
UnmapViewOfFile( (LPVOID)hModule );
|
|
return 1;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* The PE Library Loader frontend.
|
|
* FIXME: handle the flags.
|
|
* internal module handling should be made better here (and in builtin.c)
|
|
*/
|
|
HMODULE32 PE_LoadLibraryEx32A (LPCSTR name, PDB32 *process,
|
|
HFILE32 hFile, DWORD flags)
|
|
{
|
|
OFSTRUCT ofs;
|
|
HMODULE32 hModule;
|
|
NE_MODULE *pModule;
|
|
WINE_MODREF *wm;
|
|
|
|
if ((hModule = MODULE_FindModule32( process, name ))) {
|
|
for (wm= process->modref_list;wm;wm=wm->next)
|
|
if (wm->module == hModule)
|
|
return hModule;
|
|
/* Since MODULE_FindModule32 uses the modref chain too, the
|
|
* module MUST have been found above. If not, something has gone
|
|
* terribly wrong.
|
|
*/
|
|
assert(0);
|
|
}
|
|
/* try to load builtin, enabled modules first */
|
|
if ((hModule = BUILTIN32_LoadModule( name, FALSE, process )))
|
|
return hModule;
|
|
|
|
/* try to load the specified dll/exe */
|
|
if (HFILE_ERROR32==(hFile=OpenFile32(name,&ofs,OF_READ))) {
|
|
/* Now try the built-in even if disabled */
|
|
if ((hModule = BUILTIN32_LoadModule( name, TRUE, process ))) {
|
|
WARN( module, "Could not load external DLL '%s', using built-in module.\n", name );
|
|
return hModule;
|
|
}
|
|
return 0;
|
|
}
|
|
/* will go away ... */
|
|
if ((hModule = MODULE_CreateDummyModule( &ofs )) < 32) {
|
|
_lclose32(hFile);
|
|
return hModule;
|
|
}
|
|
pModule = (NE_MODULE *)GlobalLock16( hModule );
|
|
pModule->flags = NE_FFLAGS_WIN32;
|
|
/* .. */
|
|
|
|
wm=(WINE_MODREF*)HeapAlloc(process->heap,HEAP_ZERO_MEMORY,sizeof(*wm));
|
|
wm->type = MODULE32_PE;
|
|
/* NOTE: fixup_imports takes care of the correct order */
|
|
wm->next = process->modref_list;
|
|
process->modref_list = wm;
|
|
|
|
wm->module = pModule->module32 = PE_LoadImage( hFile );
|
|
|
|
CloseHandle( hFile );
|
|
if (wm->module < 32)
|
|
{
|
|
process->modref_list = wm->next;
|
|
FreeLibrary16( hModule);
|
|
HeapFree(process->heap,0,wm);
|
|
ERR(win32,"can't load %s\n",ofs.szPathName);
|
|
return 0;
|
|
}
|
|
|
|
/* (possible) recursion */
|
|
if (!PE_MapImage(process,wm,&ofs,flags)) {
|
|
/* ERROR cleanup ... */
|
|
WINE_MODREF **xwm;
|
|
|
|
ERR(win32,"couldn't load %s\n",ofs.szPathName);
|
|
/* unlink from process modref chain */
|
|
for ( xwm=&(process->modref_list);
|
|
*xwm && (*xwm!=wm);
|
|
xwm=&((*xwm)->next)
|
|
) /* EMPTY */;
|
|
if (*xwm)
|
|
*xwm=(*xwm)->next;
|
|
|
|
return 0;
|
|
}
|
|
pModule->module32 = wm->module;
|
|
if (wm->binfmt.pe.pe_export)
|
|
SNOOP_RegisterDLL(wm->module,wm->modname,wm->binfmt.pe.pe_export->NumberOfFunctions);
|
|
return wm->module;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Load the PE main .EXE. All other loading is done by PE_LoadLibraryEx32A
|
|
* FIXME: this function should use PE_LoadLibraryEx32A, but currently can't
|
|
* due to the PROCESS_Create stuff.
|
|
*/
|
|
HINSTANCE16 PE_LoadModule( LPCSTR name, LPCSTR cmd_line,
|
|
LPCSTR env, UINT16 show_cmd )
|
|
{
|
|
HMODULE16 hModule16;
|
|
HMODULE32 hModule32;
|
|
HINSTANCE16 hInstance;
|
|
NE_MODULE *pModule;
|
|
HFILE32 hFile;
|
|
OFSTRUCT ofs;
|
|
THDB *thdb = THREAD_Current();
|
|
PDB32 *process;
|
|
WINE_MODREF *wm;
|
|
|
|
if ((hFile = OpenFile32( name, &ofs, OF_READ )) == HFILE_ERROR32)
|
|
return 2; /* File not found */
|
|
|
|
if ((hModule16 = MODULE_CreateDummyModule( &ofs )) < 32) return hModule16;
|
|
pModule = (NE_MODULE *)GlobalLock16( hModule16 );
|
|
pModule->flags = NE_FFLAGS_WIN32;
|
|
|
|
pModule->module32 = hModule32 = PE_LoadImage( hFile );
|
|
if (hModule32 < 32) return 21;
|
|
|
|
hInstance = NE_CreateInstance( pModule, NULL, (cmd_line == NULL) );
|
|
if (cmd_line &&
|
|
!(PE_HEADER(hModule32)->FileHeader.Characteristics & IMAGE_FILE_DLL))
|
|
{
|
|
PROCESS_INFORMATION info;
|
|
PDB32 *pdb = PROCESS_Create( pModule, cmd_line, env,
|
|
hInstance, 0, show_cmd, &info );
|
|
TDB *pTask = (TDB *)GlobalLock16( pdb->task );
|
|
thdb = pTask->thdb;
|
|
/* we don't need the handles for now */
|
|
CloseHandle( info.hThread );
|
|
CloseHandle( info.hProcess );
|
|
}
|
|
|
|
process = thdb->process;
|
|
|
|
wm=(WINE_MODREF*)HeapAlloc(process->heap,HEAP_ZERO_MEMORY,sizeof(*wm));
|
|
wm->type = MODULE32_PE;
|
|
/* NOTE: fixup_imports takes care of the correct order */
|
|
wm->next = process->modref_list;
|
|
wm->module = hModule32;
|
|
process->modref_list = wm;
|
|
if (!PE_MapImage( process, wm, &ofs, 0 ))
|
|
{
|
|
/* FIXME: should destroy the task created and free referenced stuff */
|
|
return 0;
|
|
}
|
|
pModule->module32 = wm->module;
|
|
/* FIXME: Yuck. Is there no other good place to do that? */
|
|
PE_InitTls( thdb );
|
|
return hInstance;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* PE_UnloadImage [internal]
|
|
*/
|
|
int PE_UnloadImage( HMODULE32 hModule )
|
|
{
|
|
FIXME(win32,"stub.\n");
|
|
/* free resources, image, unmap */
|
|
return 1;
|
|
}
|
|
|
|
/* Called if the library is loaded or freed.
|
|
* NOTE: if a thread attaches a DLL, the current thread will only do
|
|
* DLL_PROCESS_ATTACH. Only new created threads do DLL_THREAD_ATTACH
|
|
* (SDK)
|
|
*/
|
|
static void PE_InitDLL(WINE_MODREF *wm, DWORD type,LPVOID lpReserved)
|
|
{
|
|
if (wm->type!=MODULE32_PE)
|
|
return;
|
|
if (type==DLL_PROCESS_ATTACH)
|
|
wm->binfmt.pe.flags |= PE_MODREF_PROCESS_ATTACHED;
|
|
|
|
/* DLL_ATTACH_PROCESS:
|
|
* lpreserved is NULL for dynamic loads, not-NULL for static loads
|
|
* DLL_DETACH_PROCESS:
|
|
* lpreserved is NULL if called by FreeLibrary, not-NULL otherwise
|
|
* the SDK doesn't mention anything for DLL_THREAD_*
|
|
*/
|
|
|
|
/* Is this a library? And has it got an entrypoint? */
|
|
if ((PE_HEADER(wm->module)->FileHeader.Characteristics & IMAGE_FILE_DLL) &&
|
|
(PE_HEADER(wm->module)->OptionalHeader.AddressOfEntryPoint)
|
|
) {
|
|
FARPROC32 entry = (FARPROC32)RVA_PTR( wm->module,
|
|
OptionalHeader.AddressOfEntryPoint );
|
|
TRACE(relay, "CallTo32(entryproc=%p,module=%08x,type=%ld,res=%p)\n",
|
|
entry, wm->module, type, lpReserved );
|
|
entry( wm->module, type, lpReserved );
|
|
}
|
|
}
|
|
|
|
/* Call the DLLentry function of all dlls used by that process.
|
|
* (NOTE: this may recursively call this function (if a library calls
|
|
* LoadLibrary) ... but it won't matter)
|
|
*/
|
|
void PE_InitializeDLLs(PDB32 *process,DWORD type,LPVOID lpReserved) {
|
|
WINE_MODREF *wm;
|
|
|
|
for (wm = process->modref_list;wm;wm=wm->next) {
|
|
PE_MODREF *pem = NULL;
|
|
if (wm->type!=MODULE32_PE)
|
|
continue;
|
|
pem = &(wm->binfmt.pe);
|
|
if (pem->flags & PE_MODREF_NO_DLL_CALLS)
|
|
continue;
|
|
if (type==DLL_PROCESS_ATTACH) {
|
|
if (pem->flags & PE_MODREF_PROCESS_ATTACHED)
|
|
continue;
|
|
}
|
|
PE_InitDLL( wm, type, lpReserved );
|
|
}
|
|
}
|
|
|
|
void PE_InitTls(THDB *thdb)
|
|
{
|
|
WINE_MODREF *wm;
|
|
PE_MODREF *pem;
|
|
IMAGE_NT_HEADERS *peh;
|
|
DWORD size,datasize;
|
|
LPVOID mem;
|
|
LPIMAGE_TLS_DIRECTORY pdir;
|
|
PDB32 *pdb = thdb->process;
|
|
int delta;
|
|
|
|
for (wm = pdb->modref_list;wm;wm=wm->next) {
|
|
if (wm->type!=MODULE32_PE)
|
|
continue;
|
|
pem = &(wm->binfmt.pe);
|
|
peh = PE_HEADER(wm->module);
|
|
delta = wm->module - peh->OptionalHeader.ImageBase;
|
|
if (!peh->OptionalHeader.DataDirectory[IMAGE_FILE_THREAD_LOCAL_STORAGE].VirtualAddress)
|
|
continue;
|
|
pdir = (LPVOID)(wm->module + peh->OptionalHeader.
|
|
DataDirectory[IMAGE_FILE_THREAD_LOCAL_STORAGE].VirtualAddress);
|
|
|
|
|
|
if (!(pem->flags & PE_MODREF_TLS_ALLOCED)) {
|
|
pem->tlsindex = THREAD_TlsAlloc(thdb);
|
|
*(LPDWORD)AdjustPtr(pdir->AddressOfIndex,delta)
|
|
=pem->tlsindex;
|
|
}
|
|
pem->flags |= PE_MODREF_TLS_ALLOCED;
|
|
datasize= pdir->EndAddressOfRawData-pdir->StartAddressOfRawData;
|
|
size = datasize + pdir->SizeOfZeroFill;
|
|
mem=VirtualAlloc(0,size,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
|
|
memcpy(mem,
|
|
AdjustPtr(pdir->StartAddressOfRawData,delta),
|
|
datasize);
|
|
|
|
/* don't use TlsSetValue, we are in the wrong thread */
|
|
if (pdir->AddressOfCallBacks) {
|
|
LPIMAGE_TLS_CALLBACK *cbs =
|
|
(LPIMAGE_TLS_CALLBACK *)
|
|
AdjustPtr(pdir->AddressOfCallBacks, delta);
|
|
|
|
if (*cbs) {
|
|
FIXME(win32, "TLS Callbacks aren't going to be called\n");
|
|
}
|
|
}
|
|
thdb->tls_array[pem->tlsindex] = mem;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* DisableThreadLibraryCalls (KERNEL32.74)
|
|
* Don't call DllEntryPoint for DLL_THREAD_{ATTACH,DETACH} if set.
|
|
*/
|
|
BOOL32 WINAPI DisableThreadLibraryCalls(HMODULE32 hModule)
|
|
{
|
|
WINE_MODREF *wm;
|
|
|
|
for (wm=PROCESS_Current()->modref_list;wm;wm=wm->next)
|
|
if ((wm->module == hModule) && (wm->type==MODULE32_PE))
|
|
wm->binfmt.pe.flags|=PE_MODREF_NO_DLL_CALLS;
|
|
return TRUE;
|
|
}
|