Use a memory mapping instead of file I/O to load 16-bit modules.

This commit is contained in:
Alexandre Julliard 2005-05-19 12:05:28 +00:00
parent a890293f33
commit 8eb1630ce1
4 changed files with 307 additions and 403 deletions

View File

@ -61,11 +61,12 @@ typedef struct _NE_MODULE
WORD ne_swaparea; /* 3c Min. swap area size */
WORD ne_expver; /* 3e Expected Windows version */
/* From here, these are extra fields not present in normal Windows */
HMODULE module32; /* 40 PE module handle for Win32 modules */
HMODULE16 self; /* 44 Handle for this module */
WORD self_loading_sel; /* 46 Selector used for self-loading apps. */
LPVOID rsrc32_map; /* 48 HRSRC 16->32 map (for 32-bit modules) */
HANDLE fd; /* 4c handle to the binary file */
HMODULE module32; /* PE module handle for Win32 modules */
HMODULE16 self; /* Handle for this module */
WORD self_loading_sel; /* Selector used for self-loading apps. */
LPVOID rsrc32_map; /* HRSRC 16->32 map (for 32-bit modules) */
LPCVOID mapping; /* mapping of the binary file */
SIZE_T mapping_size; /* size of the file mapping */
} NE_MODULE;
typedef struct
@ -132,6 +133,14 @@ extern THHOOK *pThhook;
#define NE_MODULE_NAME(pModule) \
(((OFSTRUCT *)((char*)(pModule) + (pModule)->fileinfo))->szPathName)
#define NE_GET_DATA(pModule,offset,size) \
((const void *)(((offset)+(size) <= pModule->mapping_size) ? \
(const char *)pModule->mapping + (offset) : NULL))
#define NE_READ_DATA(pModule,buffer,offset,size) \
(((offset)+(size) <= pModule->mapping_size) ? \
(memcpy( buffer, (const char *)pModule->mapping + (offset), (size) ), TRUE) : FALSE)
#define CURRENT_STACK16 ((STACK16FRAME*)MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved))
#define CURRENT_DS (CURRENT_STACK16->ds)
@ -158,7 +167,6 @@ extern WORD NE_GetOrdinal( HMODULE16 hModule, const char *name );
extern FARPROC16 WINAPI NE_GetEntryPoint( HMODULE16 hModule, WORD ordinal );
extern FARPROC16 NE_GetEntryPointEx( HMODULE16 hModule, WORD ordinal, BOOL16 snoop );
extern BOOL16 NE_SetEntryPoint( HMODULE16 hModule, WORD ordinal, WORD offset );
extern HANDLE NE_OpenFile( NE_MODULE *pModule );
extern DWORD NE_StartTask(void);
/* ne_segment.c */

View File

@ -564,46 +564,6 @@ BOOL16 NE_SetEntryPoint( HMODULE16 hModule, WORD ordinal, WORD offset )
}
/***********************************************************************
* NE_OpenFile
*/
HANDLE NE_OpenFile( NE_MODULE *pModule )
{
HANDLE handle;
char *name = NE_MODULE_NAME( pModule );
TRACE("(%p)\n", pModule );
if (pModule->fd)
{
if (!DuplicateHandle( GetCurrentProcess(), pModule->fd,
GetCurrentProcess(), &handle, 0, FALSE,
DUPLICATE_SAME_ACCESS )) handle = INVALID_HANDLE_VALUE;
}
else
{
handle = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, 0 );
}
if (handle == INVALID_HANDLE_VALUE)
ERR( "Can't open file '%s' for module %04x\n", name, pModule->self );
TRACE("opened '%s' -> %p\n", name, handle);
return handle;
}
/* wrapper for SetFilePointer and ReadFile */
static BOOL read_data( HANDLE handle, LONG offset, void *buffer, DWORD size )
{
DWORD result;
if (SetFilePointer( handle, offset, NULL, SEEK_SET ) == INVALID_SET_FILE_POINTER) return FALSE;
if (!ReadFile( handle, buffer, size, &result, NULL )) return FALSE;
return (result == size);
}
/***********************************************************************
* build_bundle_data
*
@ -676,24 +636,39 @@ static void *build_bundle_data( NE_MODULE *pModule, void *dest, const BYTE *tabl
*
* Build the in-memory module from the on-disk data.
*/
static HMODULE16 build_module( const IMAGE_DOS_HEADER *mz_header, const IMAGE_OS2_HEADER *ne_header,
HANDLE handle, LPCSTR path, const void *fastload,
unsigned int fastload_offset, unsigned int fastload_length )
static HMODULE16 build_module( const void *mapping, SIZE_T mapping_size, LPCSTR path )
{
const IMAGE_DOS_HEADER *mz_header = mapping;
const IMAGE_OS2_HEADER *ne_header;
const struct ne_segment_table_entry_s *pSeg;
const void *ptr;
int i;
size_t size;
HMODULE16 hModule;
NE_MODULE *pModule;
BYTE *buffer, *pData, *ptr;
BYTE *buffer, *pData, *end;
OFSTRUCT *ofs;
struct ne_segment_table_entry_s *pSeg;
/* Read a block from either the file or the fast-load area. */
#define READ(offset,size,buffer) \
((fastload && ((offset) >= fastload_offset) && \
((offset)+(size) <= fastload_offset+fastload_length)) ? \
(memcpy( buffer, (const char *)fastload+(offset)-fastload_offset, (size) ), TRUE) : \
(handle && read_data( handle, (offset), (buffer), (size))))
if (mapping_size < sizeof(*mz_header)) return ERROR_BAD_FORMAT;
if (mz_header->e_magic != IMAGE_DOS_SIGNATURE) return ERROR_BAD_FORMAT;
ne_header = (const IMAGE_OS2_HEADER *)((const char *)mapping + mz_header->e_lfanew);
if (mz_header->e_lfanew + sizeof(*ne_header) > mapping_size) return ERROR_BAD_FORMAT;
if (ne_header->ne_magic == IMAGE_NT_SIGNATURE) return 21; /* win32 exe */
if (ne_header->ne_magic == IMAGE_OS2_SIGNATURE_LX)
{
MESSAGE("Sorry, %s is an OS/2 linear executable (LX) file!\n", path);
return 12;
}
if (ne_header->ne_magic != IMAGE_OS2_SIGNATURE) return ERROR_BAD_FORMAT;
/* We now have a valid NE header */
/* check to be able to fall back to loading OS/2 programs as DOS
* FIXME: should this check be reversed in order to be less strict?
* (only fail for OS/2 ne_exetyp 0x01 here?) */
if ((ne_header->ne_exetyp != 0x02 /* Windows */)
&& (ne_header->ne_exetyp != 0x04) /* Windows 386 */)
return ERROR_BAD_FORMAT;
size = sizeof(NE_MODULE) +
/* segment table */
@ -724,28 +699,23 @@ static HMODULE16 build_module( const IMAGE_DOS_HEADER *mz_header, const IMAGE_OS
/* check programs for default minimal stack size */
if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE) && (pModule->ne_stack < 0x1400))
pModule->ne_stack = 0x1400;
pModule->module32 = 0;
pModule->self = hModule;
pModule->self_loading_sel = 0;
pModule->self = hModule;
pModule->mapping = mapping;
pModule->mapping_size = mapping_size;
pData = (BYTE *)(pModule + 1);
/* Clear internal Wine flags in case they are set in the EXE file */
pModule->ne_flags &= ~(NE_FFLAGS_BUILTIN | NE_FFLAGS_WIN32);
/* allocate temporary buffer for segment and entry tables */
if (!(buffer = HeapAlloc( GetProcessHeap(), 0,
max( ne_header->ne_cseg * sizeof(*pSeg), ne_header->ne_cbenttab ) )))
goto failed;
/* Get the segment table */
pModule->ne_segtab = pData - (BYTE *)pModule;
if (!READ( mz_header->e_lfanew + ne_header->ne_segtab,
ne_header->ne_cseg * sizeof(struct ne_segment_table_entry_s), buffer ))
if (!(pSeg = NE_GET_DATA( pModule, mz_header->e_lfanew + ne_header->ne_segtab,
ne_header->ne_cseg * sizeof(struct ne_segment_table_entry_s) )))
goto failed;
pSeg = (struct ne_segment_table_entry_s *)buffer;
for (i = ne_header->ne_cseg; i > 0; i--, pSeg++)
{
memcpy( pData, pSeg, sizeof(*pSeg) );
@ -757,8 +727,8 @@ static HMODULE16 build_module( const IMAGE_DOS_HEADER *mz_header, const IMAGE_OS
if (ne_header->ne_rsrctab < ne_header->ne_restab)
{
pModule->ne_rsrctab = pData - (BYTE *)pModule;
if (!READ( mz_header->e_lfanew + ne_header->ne_rsrctab,
ne_header->ne_restab - ne_header->ne_rsrctab, pData )) goto failed;
if (!NE_READ_DATA( pModule, pData, mz_header->e_lfanew + ne_header->ne_rsrctab,
ne_header->ne_restab - ne_header->ne_rsrctab )) goto failed;
pData += ne_header->ne_restab - ne_header->ne_rsrctab;
}
else pModule->ne_rsrctab = 0; /* No resource table */
@ -766,8 +736,8 @@ static HMODULE16 build_module( const IMAGE_DOS_HEADER *mz_header, const IMAGE_OS
/* Get the resident names table */
pModule->ne_restab = pData - (BYTE *)pModule;
if (!READ( mz_header->e_lfanew + ne_header->ne_restab,
ne_header->ne_modtab - ne_header->ne_restab, pData )) goto failed;
if (!NE_READ_DATA( pModule, pData, mz_header->e_lfanew + ne_header->ne_restab,
ne_header->ne_modtab - ne_header->ne_restab )) goto failed;
pData += ne_header->ne_modtab - ne_header->ne_restab;
/* Get the module references table */
@ -775,8 +745,8 @@ static HMODULE16 build_module( const IMAGE_DOS_HEADER *mz_header, const IMAGE_OS
if (ne_header->ne_cmod > 0)
{
pModule->ne_modtab = pData - (BYTE *)pModule;
if (!READ( mz_header->e_lfanew + ne_header->ne_modtab,
ne_header->ne_cmod * sizeof(WORD), pData )) goto failed;
if (!NE_READ_DATA( pModule, pData, mz_header->e_lfanew + ne_header->ne_modtab,
ne_header->ne_cmod * sizeof(WORD) )) goto failed;
pData += ne_header->ne_cmod * sizeof(WORD);
}
else pModule->ne_modtab = 0; /* No module references */
@ -784,23 +754,21 @@ static HMODULE16 build_module( const IMAGE_DOS_HEADER *mz_header, const IMAGE_OS
/* Get the imported names table */
pModule->ne_imptab = pData - (BYTE *)pModule;
if (!READ( mz_header->e_lfanew + ne_header->ne_imptab,
ne_header->ne_enttab - ne_header->ne_imptab,
pData )) goto failed;
if (!NE_READ_DATA( pModule, pData, mz_header->e_lfanew + ne_header->ne_imptab,
ne_header->ne_enttab - ne_header->ne_imptab )) goto failed;
pData += ne_header->ne_enttab - ne_header->ne_imptab;
/* Load entry table, convert it to the optimized version used by Windows */
pModule->ne_enttab = pData - (BYTE *)pModule;
if (!READ( mz_header->e_lfanew + ne_header->ne_enttab,
ne_header->ne_cbenttab, buffer )) goto failed;
ptr = build_bundle_data( pModule, pData, buffer );
if (!(ptr = NE_GET_DATA( pModule, mz_header->e_lfanew + ne_header->ne_enttab,
ne_header->ne_cbenttab ))) goto failed;
end = build_bundle_data( pModule, pData, ptr );
pData += ne_header->ne_cbenttab + sizeof(ET_BUNDLE) +
2 * (ne_header->ne_cbenttab - ne_header->ne_cmovent*6);
if (ptr > pData)
if (end > pData)
{
FIXME( "not enough space for entry table for %s\n", debugstr_a(path) );
goto failed;
@ -823,8 +791,8 @@ static HMODULE16 build_module( const IMAGE_DOS_HEADER *mz_header, const IMAGE_OS
pModule->nrname_handle = GlobalAlloc16( 0, ne_header->ne_cbnrestab );
if (!pModule->nrname_handle) goto failed;
FarSetOwner16( pModule->nrname_handle, hModule );
ptr = GlobalLock16( pModule->nrname_handle );
if (!read_data( handle, ne_header->ne_nrestab, ptr, ne_header->ne_cbnrestab ))
buffer = GlobalLock16( pModule->nrname_handle );
if (!NE_READ_DATA( pModule, buffer, ne_header->ne_nrestab, ne_header->ne_cbnrestab ))
{
GlobalFree16( pModule->nrname_handle );
goto failed;
@ -847,92 +815,12 @@ static HMODULE16 build_module( const IMAGE_DOS_HEADER *mz_header, const IMAGE_OS
}
else pModule->dlls_to_init = 0;
HeapFree( GetProcessHeap(), 0, buffer );
NE_RegisterModule( pModule );
if (handle)
{
UINT drive_type = GetDriveTypeA( path );
/* keep the file handle open if not on a removable media */
if (drive_type != DRIVE_REMOVABLE && drive_type != DRIVE_CDROM)
DuplicateHandle( GetCurrentProcess(), handle,
GetCurrentProcess(), &pModule->fd, 0, FALSE,
DUPLICATE_SAME_ACCESS );
}
return hModule;
failed:
HeapFree( GetProcessHeap(), 0, buffer );
GlobalFree16( hModule );
return ERROR_BAD_FORMAT;
#undef READ
}
/***********************************************************************
* NE_LoadExeHeader
*/
static HMODULE16 NE_LoadExeHeader( HANDLE handle, LPCSTR path )
{
IMAGE_DOS_HEADER mz_header;
IMAGE_OS2_HEADER ne_header;
HMODULE16 hModule;
char *fastload = NULL;
unsigned int fastload_offset = 0, fastload_length = 0;
if (!read_data( handle, 0, &mz_header, sizeof(mz_header)) ||
(mz_header.e_magic != IMAGE_DOS_SIGNATURE))
return ERROR_BAD_FORMAT;
if (!read_data( handle, mz_header.e_lfanew, &ne_header, sizeof(ne_header) ))
return ERROR_BAD_FORMAT;
if (ne_header.ne_magic == IMAGE_NT_SIGNATURE) return (HMODULE16)21; /* win32 exe */
if (ne_header.ne_magic == IMAGE_OS2_SIGNATURE_LX) {
MESSAGE("Sorry, this is an OS/2 linear executable (LX) file!\n");
return (HMODULE16)12;
}
if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE) return ERROR_BAD_FORMAT;
/* We now have a valid NE header */
/* check to be able to fall back to loading OS/2 programs as DOS
* FIXME: should this check be reversed in order to be less strict?
* (only fail for OS/2 ne_exetyp 0x01 here?) */
if ((ne_header.ne_exetyp != 0x02 /* Windows */)
&& (ne_header.ne_exetyp != 0x04) /* Windows 386 */)
return ERROR_BAD_FORMAT;
/* Read the fast-load area */
if (ne_header.ne_flagsothers & NE_AFLAGS_FASTLOAD)
{
fastload_offset=ne_header.ne_pretthunks << ne_header.ne_align;
fastload_length=ne_header.ne_psegrefbytes << ne_header.ne_align;
TRACE("Using fast-load area offset=%x len=%d\n",
fastload_offset, fastload_length );
if ((fastload = HeapAlloc( GetProcessHeap(), 0, fastload_length )) != NULL)
{
if (!read_data( handle, fastload_offset, fastload, fastload_length))
{
HeapFree( GetProcessHeap(), 0, fastload );
WARN("Error reading fast-load area!\n");
fastload = NULL;
}
}
}
hModule = build_module( &mz_header, &ne_header, handle, path,
fastload, fastload_offset, fastload_length );
HeapFree( GetProcessHeap(), 0, fastload );
if (hModule >= 32)
{
SNOOP16_RegisterDLL( hModule, path );
NE_InitResourceHandler( hModule );
}
return hModule;
}
@ -992,7 +880,7 @@ static BOOL NE_LoadDLLs( NE_MODULE *pModule )
*
* Load first instance of NE module from file.
*
* pModule must point to a module structure prepared by NE_LoadExeHeader.
* pModule must point to a module structure prepared by build_module_data.
* This routine must never be called twice on a module.
*
*/
@ -1042,14 +930,33 @@ static HINSTANCE16 NE_LoadModule( LPCSTR name, BOOL lib_only )
HINSTANCE16 hInstance;
HFILE16 hFile;
OFSTRUCT ofs;
HANDLE mapping;
void *ptr;
MEMORY_BASIC_INFORMATION info;
/* Open file */
if ((hFile = OpenFile16( name, &ofs, OF_READ|OF_SHARE_DENY_WRITE )) == HFILE_ERROR16)
return ERROR_FILE_NOT_FOUND;
hModule = NE_LoadExeHeader( DosFileHandleToWin32Handle(hFile), ofs.szPathName );
mapping = CreateFileMappingW( DosFileHandleToWin32Handle(hFile), NULL, PAGE_WRITECOPY, 0, 0, NULL );
_lclose16( hFile );
if (hModule < 32) return hModule;
if (!mapping) return ERROR_BAD_FORMAT;
ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 0 );
CloseHandle( mapping );
if (!ptr) return ERROR_BAD_FORMAT;
VirtualQuery( ptr, &info, sizeof(info) );
hModule = build_module( ptr, info.RegionSize, ofs.szPathName );
if (hModule < 32)
{
UnmapViewOfFile( ptr );
return hModule;
}
SNOOP16_RegisterDLL( hModule, ofs.szPathName );
NE_InitResourceHandler( hModule );
pModule = NE_GetPtr( hModule );
@ -1079,14 +986,12 @@ static HMODULE16 NE_DoLoadBuiltinModule( const BUILTIN16_DESCRIPTOR *descr )
SEGTABLEENTRY *pSegTable;
const IMAGE_DOS_HEADER *mz_header;
const IMAGE_OS2_HEADER *ne_header;
unsigned int fastload_offset, fastload_length;
SIZE_T mapping_size;
mz_header = descr->module;
ne_header = (const IMAGE_OS2_HEADER *)((const BYTE *)mz_header + mz_header->e_lfanew);
fastload_offset = ne_header->ne_pretthunks << ne_header->ne_align;
fastload_length = ne_header->ne_psegrefbytes << ne_header->ne_align;
hModule = build_module( mz_header, ne_header, 0, descr->file_name,
descr->module, fastload_offset, fastload_length );
mapping_size = ne_header->ne_psegrefbytes << ne_header->ne_align;
hModule = build_module( descr->module, mapping_size, descr->file_name );
if (hModule < 32) return hModule;
pModule = GlobalLock16( hModule );
pModule->ne_flags |= NE_FFLAGS_BUILTIN;
@ -1502,7 +1407,7 @@ static BOOL16 NE_FreeModule( HMODULE16 hModule, BOOL call_wep )
/* Clear magic number just in case */
pModule->ne_magic = pModule->self = 0;
if (pModule->fd) CloseHandle( pModule->fd );
if (!(pModule->ne_flags & NE_FFLAGS_BUILTIN)) UnmapViewOfFile( (void *)pModule->mapping );
/* Remove it from the linked list */

View File

@ -116,162 +116,58 @@ static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
/***********************************************************************
* NE_LoadSegment
* NE_OpenFile
*/
BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
static HFILE16 NE_OpenFile( NE_MODULE *pModule )
{
SEGTABLEENTRY *pSegTable, *pSeg;
HMODULE16 *pModuleTable;
WORD count, i, offset, next_offset;
char *name = NE_MODULE_NAME( pModule );
HANDLE handle = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, 0 );
if (handle == INVALID_HANDLE_VALUE)
{
ERR( "Can't open file '%s' for module %04x\n", name, pModule->self );
return HFILE_ERROR;
}
return Win32HandleToDosFileHandle( handle );
}
/***********************************************************************
* apply_relocations
*
* Apply relocations to a segment. Helper for NE_LoadSegment.
*/
static inline BOOL apply_relocations( NE_MODULE *pModule, const struct relocation_entry_s *rep,
int count, int segnum )
{
BYTE *func_name;
char buffer[256];
int i, ordinal;
WORD offset, *sp;
HMODULE16 module;
FARPROC16 address = 0;
HANDLE hf;
DWORD res;
struct relocation_entry_s *rep, *reloc_entries;
BYTE *func_name;
int size;
char* mem;
char buffer[256];
int ordinal, additive;
unsigned short *sp;
pSegTable = NE_SEG_TABLE( pModule );
pSeg = pSegTable + segnum - 1;
if (pSeg->flags & NE_SEGFLAGS_LOADED)
{
/* self-loader ? -> already loaded it */
if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
return TRUE;
/* leave, except for DGROUP, as this may be the second instance */
if (segnum != pModule->ne_autodata)
return TRUE;
}
if (!pSeg->filepos) return TRUE; /* No file image, just return */
pModuleTable = (HMODULE16 *)((char *)pModule + pModule->ne_modtab);
hf = NE_OpenFile( pModule );
TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
segnum, pSeg->hSeg, pSeg->flags );
SetFilePointer( hf, pSeg->filepos << pModule->ne_align, NULL, SEEK_SET );
if (pSeg->size) size = pSeg->size;
else size = pSeg->minsize ? pSeg->minsize : 0x10000;
mem = GlobalLock16(pSeg->hSeg);
if (pModule->ne_flags & NE_FFLAGS_SELFLOAD && segnum > 1)
{
/* Implement self-loading segments */
SELFLOADHEADER *selfloadheader;
void *oldstack;
HANDLE hFile32;
HFILE16 hFile16;
WORD args[3];
DWORD ret;
selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
oldstack = NtCurrentTeb()->WOW32Reserved;
NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
0xff00 - sizeof(STACK16FRAME));
TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=%p,segnum=%d\n",
pModule->self,hf,segnum );
DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
0, FALSE, DUPLICATE_SAME_ACCESS );
hFile16 = Win32HandleToDosFileHandle( hFile32 );
args[2] = pModule->self;
args[1] = hFile16;
args[0] = segnum;
WOWCallback16Ex( (DWORD)selfloadheader->LoadAppSeg, WCB16_PASCAL, sizeof(args), args, &ret );
pSeg->hSeg = LOWORD(ret);
TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
_lclose16( hFile16 );
NtCurrentTeb()->WOW32Reserved = oldstack;
}
else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
ReadFile(hf, mem, size, &res, NULL);
else {
/*
The following bit of code for "iterated segments" was written without
any documentation on the format of these segments. It seems to work,
but may be missing something. If you have any doc please either send
it to me or fix the code yourself. gfm@werple.mira.net.au
*/
char* buff = HeapAlloc(GetProcessHeap(), 0, size);
char* curr = buff;
if(buff == NULL) {
WARN_(dll)("Memory exhausted!\n");
goto fail;
}
ReadFile(hf, buff, size, &res, NULL);
while(curr < buff + size) {
unsigned int rept = ((short*)curr)[0];
unsigned int len = ((short*)curr)[1];
curr += 2*sizeof(short);
for(; rept > 0; rept--) {
char* bytes = curr;
unsigned int byte;
for(byte = 0; byte < len; byte++)
*mem++ = *bytes++;
}
curr += len;
}
HeapFree(GetProcessHeap(), 0, buff);
}
pSeg->flags |= NE_SEGFLAGS_LOADED;
/* Perform exported function prolog fixups */
NE_FixupSegmentPrologs( pModule, segnum );
if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
goto succeed; /* No relocation data, we are done */
ReadFile(hf, &count, sizeof(count), &res, NULL);
if (!count) goto succeed;
TRACE("Fixups for %.*s, segment %d, hSeg %04x\n",
*((BYTE *)pModule + pModule->ne_restab),
(char *)pModule + pModule->ne_restab + 1,
segnum, pSeg->hSeg );
reloc_entries = HeapAlloc(GetProcessHeap(), 0, count * sizeof(struct relocation_entry_s));
if(reloc_entries == NULL) {
WARN("Not enough memory for relocation entries!\n");
goto fail;
}
if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
(res != count * sizeof(struct relocation_entry_s)))
{
WARN("Unable to read relocation information\n" );
goto fail;
}
HMODULE16 *pModuleTable = (HMODULE16 *)((char *)pModule + pModule->ne_modtab);
SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;
/*
* Go through the relocation table one entry at a time.
*/
rep = reloc_entries;
for (i = 0; i < count; i++, rep++)
{
/*
* Get the target address corresponding to this entry.
*/
/*
* Get the target address corresponding to this entry.
*/
/* If additive, there is no target chain list. Instead, add source
and target */
additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
rep->relocation_type &= 0x3;
switch (rep->relocation_type)
{
case NE_RELTYPE_ORDINAL:
/* If additive, there is no target chain list. Instead, add source
and target */
int additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
switch (rep->relocation_type & 3)
{
case NE_RELTYPE_ORDINAL:
module = pModuleTable[rep->target1-1];
ordinal = rep->target2;
ordinal = rep->target2;
address = NE_GetEntryPoint( module, ordinal );
if (!address)
{
@ -300,9 +196,9 @@ BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
ordinal, HIWORD(address), LOWORD(address),
NE_GetRelocAddrName( rep->address_type, additive ) );
}
break;
break;
case NE_RELTYPE_NAME:
case NE_RELTYPE_NAME:
module = pModuleTable[rep->target1-1];
func_name = (char *)pModule + pModule->ne_imptab + rep->target2;
memcpy( buffer, func_name+1, *func_name );
@ -321,51 +217,51 @@ BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
if (!address) address = (FARPROC16) 0xdeadbeef;
if (TRACE_ON(fixup))
{
NE_MODULE *pTarget = NE_GetPtr( module );
NE_MODULE *pTarget = NE_GetPtr( module );
TRACE("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
*((BYTE *)pTarget + pTarget->ne_restab),
(char *)pTarget + pTarget->ne_restab + 1,
func_name, HIWORD(address), LOWORD(address),
NE_GetRelocAddrName( rep->address_type, additive ) );
}
break;
break;
case NE_RELTYPE_INTERNAL:
if ((rep->target1 & 0xff) == 0xff)
{
address = NE_GetEntryPoint( pModule->self, rep->target2 );
}
else
{
case NE_RELTYPE_INTERNAL:
if ((rep->target1 & 0xff) == 0xff)
{
address = NE_GetEntryPoint( pModule->self, rep->target2 );
}
else
{
address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
}
}
TRACE("%d: %04x:%04x %s\n",
i + 1, HIWORD(address), LOWORD(address),
NE_GetRelocAddrName( rep->address_type, additive ) );
break;
TRACE("%d: %04x:%04x %s\n",
i + 1, HIWORD(address), LOWORD(address),
NE_GetRelocAddrName( rep->address_type, additive ) );
break;
case NE_RELTYPE_OSFIXUP:
/* Relocation type 7:
*
* These appear to be used as fixups for the Windows
* floating point emulator. Let's just ignore them and
* try to use the hardware floating point. Linux should
* successfully emulate the coprocessor if it doesn't
* exist.
*/
TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
i + 1, rep->relocation_type, rep->offset,
rep->target1, rep->target2,
NE_GetRelocAddrName( rep->address_type, additive ) );
continue;
}
case NE_RELTYPE_OSFIXUP:
/* Relocation type 7:
*
* These appear to be used as fixups for the Windows
* floating point emulator. Let's just ignore them and
* try to use the hardware floating point. Linux should
* successfully emulate the coprocessor if it doesn't
* exist.
*/
TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
i + 1, rep->relocation_type, rep->offset,
rep->target1, rep->target2,
NE_GetRelocAddrName( rep->address_type, additive ) );
continue;
}
offset = rep->offset;
offset = rep->offset;
/* Apparently, high bit of address_type is sometimes set; */
/* we ignore it for now */
if (rep->address_type > NE_RADDR_OFFSET32)
if (rep->address_type > NE_RADDR_OFFSET32)
{
char module[10];
GetModuleName16( pModule->self, module, sizeof(module) );
@ -383,17 +279,17 @@ BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
*(BYTE *)sp += LOBYTE((int)address);
break;
case NE_RADDR_OFFSET16:
*sp += LOWORD(address);
*sp += LOWORD(address);
break;
case NE_RADDR_POINTER32:
*sp += LOWORD(address);
*(sp+1) = HIWORD(address);
*sp += LOWORD(address);
*(sp+1) = HIWORD(address);
break;
case NE_RADDR_SELECTOR:
/* Borland creates additive records with offset zero. Strange, but OK */
/* Borland creates additive records with offset zero. Strange, but OK */
if (*sp)
ERR("Additive selector to %04x.Please report\n",*sp);
else
else
*sp = HIWORD(address);
break;
default:
@ -404,6 +300,8 @@ BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
{
do
{
WORD next_offset;
sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
next_offset = *sp;
TRACE(" %04x:%04x\n", offset, *sp );
@ -430,11 +328,6 @@ BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
} while (offset != 0xffff);
}
}
HeapFree(GetProcessHeap(), 0, reloc_entries);
succeed:
CloseHandle(hf);
return TRUE;
unknown:
@ -442,14 +335,125 @@ unknown:
"TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
i + 1, rep->address_type, rep->relocation_type,
rep->offset, rep->target1, rep->target2);
HeapFree(GetProcessHeap(), 0, reloc_entries);
fail:
CloseHandle(hf);
return FALSE;
}
/***********************************************************************
* NE_LoadSegment
*/
BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
{
WORD count;
DWORD pos;
const struct relocation_entry_s *rep;
int size;
SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;
if (pSeg->flags & NE_SEGFLAGS_LOADED)
{
/* self-loader ? -> already loaded it */
if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
return TRUE;
/* leave, except for DGROUP, as this may be the second instance */
if (segnum != pModule->ne_autodata)
return TRUE;
}
if (!pSeg->filepos) return TRUE; /* No file image, just return */
TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
segnum, pSeg->hSeg, pSeg->flags );
pos = pSeg->filepos << pModule->ne_align;
if (pSeg->size) size = pSeg->size;
else size = pSeg->minsize ? pSeg->minsize : 0x10000;
if (pModule->ne_flags & NE_FFLAGS_SELFLOAD && segnum > 1)
{
/* Implement self-loading segments */
SELFLOADHEADER *selfloadheader;
void *oldstack;
HFILE16 hFile16;
WORD args[3];
DWORD ret;
selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
oldstack = NtCurrentTeb()->WOW32Reserved;
NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
0xff00 - sizeof(STACK16FRAME));
hFile16 = NE_OpenFile( pModule );
TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=%x,segnum=%d\n",
pModule->self,hFile16,segnum );
args[2] = pModule->self;
args[1] = hFile16;
args[0] = segnum;
WOWCallback16Ex( (DWORD)selfloadheader->LoadAppSeg, WCB16_PASCAL, sizeof(args), args, &ret );
pSeg->hSeg = LOWORD(ret);
TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
_lclose16( hFile16 );
NtCurrentTeb()->WOW32Reserved = oldstack;
}
else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
{
void *mem = GlobalLock16(pSeg->hSeg);
if (!NE_READ_DATA( pModule, mem, pos, size ))
return FALSE;
pos += size;
}
else
{
/*
The following bit of code for "iterated segments" was written without
any documentation on the format of these segments. It seems to work,
but may be missing something.
*/
const char *buff = NE_GET_DATA( pModule, pos, size );
const char* curr = buff;
char *mem = GlobalLock16(pSeg->hSeg);
pos += size;
if (buff == NULL) return FALSE;
while(curr < buff + size) {
unsigned int rept = ((short*)curr)[0];
unsigned int len = ((short*)curr)[1];
curr += 2*sizeof(short);
while (rept--)
{
memcpy( mem, curr, len );
mem += len;
}
curr += len;
}
}
pSeg->flags |= NE_SEGFLAGS_LOADED;
/* Perform exported function prolog fixups */
NE_FixupSegmentPrologs( pModule, segnum );
if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
return TRUE; /* No relocation data, we are done */
if (!NE_READ_DATA( pModule, &count, pos, sizeof(count) ) || !count) return TRUE;
pos += sizeof(count);
TRACE("Fixups for %.*s, segment %d, hSeg %04x\n",
*((BYTE *)pModule + pModule->ne_restab),
(char *)pModule + pModule->ne_restab + 1,
segnum, pSeg->hSeg );
if (!(rep = NE_GET_DATA( pModule, pos, count * sizeof(struct relocation_entry_s) )))
return FALSE;
return apply_relocations( pModule, rep, count, segnum );
}
/***********************************************************************
* NE_LoadAllSegments
*/
@ -460,7 +464,6 @@ BOOL NE_LoadAllSegments( NE_MODULE *pModule )
if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
{
HANDLE hf;
HFILE16 hFile16;
HGLOBAL16 sel;
/* Handle self-loading modules */
@ -484,8 +487,7 @@ BOOL NE_LoadAllSegments( NE_MODULE *pModule )
NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
0xff00 - sizeof(STACK16FRAME) );
hf = NE_OpenFile(pModule);
hFile16 = Win32HandleToDosFileHandle( hf );
hFile16 = NE_OpenFile(pModule);
TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
pModule->self,hFile16);
args[1] = pModule->self;

View File

@ -330,53 +330,42 @@ static NE_NAMEINFO *NE_FindResourceFromType( LPBYTE pResTab, NE_TYPEINFO *pTypeI
HGLOBAL16 WINAPI NE_DefResourceHandler( HGLOBAL16 hMemObj, HMODULE16 hModule,
HRSRC16 hRsrc )
{
HANDLE fd;
HGLOBAL16 handle;
WORD sizeShift;
NE_NAMEINFO* pNameInfo;
NE_MODULE* pModule = NE_GetPtr( hModule );
if (pModule && (pModule->ne_flags & NE_FFLAGS_BUILTIN))
if (!pModule) return 0;
sizeShift = *(WORD *)((char *)pModule + pModule->ne_rsrctab);
pNameInfo = (NE_NAMEINFO *)((char *)pModule + hRsrc);
if ( hMemObj )
handle = GlobalReAlloc16( hMemObj, pNameInfo->length << sizeShift, 0 );
else
handle = AllocResource16( hModule, hRsrc, 0 );
if (handle)
{
HGLOBAL16 handle;
WORD sizeShift = *(WORD *)((char *)pModule + pModule->ne_rsrctab);
NE_NAMEINFO* pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
if ( hMemObj )
handle = GlobalReAlloc16( hMemObj, pNameInfo->length << sizeShift, 0 );
else
handle = AllocResource16( hModule, hRsrc, 0 );
if ( handle )
if (pModule->ne_flags & NE_FFLAGS_BUILTIN)
{
/* NOTE: hRsrcMap points to start of built-in resource data */
memcpy( GlobalLock16( handle ),
(char *)pModule->rsrc32_map + (pNameInfo->offset << sizeShift),
pNameInfo->length << sizeShift );
}
return handle;
}
if (pModule && (fd = NE_OpenFile( pModule )) != INVALID_HANDLE_VALUE)
{
HGLOBAL16 handle;
WORD sizeShift = *(WORD *)((char *)pModule + pModule->ne_rsrctab);
NE_NAMEINFO* pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
TRACE("loading, pos=%d, len=%d\n",
(int)pNameInfo->offset << sizeShift,
(int)pNameInfo->length << sizeShift );
if( hMemObj )
handle = GlobalReAlloc16( hMemObj, pNameInfo->length << sizeShift, 0 );
else
handle = AllocResource16( hModule, hRsrc, 0 );
if( handle )
{
DWORD res;
SetFilePointer( fd, (int)pNameInfo->offset << sizeShift, NULL, SEEK_SET );
ReadFile( fd, GlobalLock16( handle ), (int)pNameInfo->length << sizeShift,
&res, NULL );
if (!NE_READ_DATA( pModule, GlobalLock16( handle ),
(int)pNameInfo->offset << sizeShift,
(int)pNameInfo->length << sizeShift ))
{
GlobalFree16( handle );
handle = 0;
}
}
CloseHandle(fd);
return handle;
}
return (HGLOBAL16)0;
return handle;
}