1
0
Fork 0
mirror of synced 2025-03-07 03:53:26 +01:00
wine/loader/ne/segment.c
Alexandre Julliard 46ea8b3f73 Release 980503
Thu Apr 30 16:28:12 1998  James Juran <jrj120@psu.edu>

	* [scheduler/process.c]
	Implemented GetExitCodeProcess.  The code is a direct translation
	of GetExitCodeThread.

Mon Apr 27 22:20:25 1998  Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>

	* [loader/pe_image.c]
	Unload dummy module when PE_LoadLibraryEx32A fails with
	PE_LoadImage (makes Encarta 98 installer proceed).

	* [files/drive.c]
	Make GetDriveType16 return DRIVE_REMOVABLE for TYPE_CDROM.
	Make GetCurrentDirectory32 behave like the code does and not
	like the help describes.

	* [files/profile.c]
	Revoke recent change in PROFILE_GetSection and try better 
	handling of special case.

	* [include/windows.h]
	Change definition of ACCEL32.

	* [misc/commdlg.c]
	Replace the GetXXXFilename32 macros by normal code.
	Fix two reported bugs in my changes to commdlg.

	* [windows/win.c]
	Add a hook to catch bogus WM_SIZE messages by emitting a warning
	in the appropriate case.

	* [objects/bitmap.c]
	Reject unreasonbable large size arguments in
	CreateCompatibleBitmap32 and add an fixme for that situation.

Sun Apr 26 18:30:07 1998  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [include/ldt.h] [debugger/*.c] [miscemu/instr.c]
	Added IS_SELECTOR_SYSTEM and IS_SELECTOR_32BIT macros.
	Make instruction emulation support system selectors.

	* [loader/*.c]
	Started moving NE specific functions to the new loader/ne
	directory.

	* [memory/environ.c]
	Enforce the 127 chars limit only when creating the environment of
	a Win16 process.

Sun Apr 26 12:22:23 1998  Andreas Mohr <100.30936@germany.net>

	* [files/file.c]
	Fixed an incredible typo in CopyFile32A that made it unusable
	since a rewrite in 970112 (!!).

	* [files/directory.c]
	Fixed GetTempPath32A/W to include trailing backslash.

	* [misc/ver.c]
	Make find_pe_resource "work" with corrupt files.

	* [misc/wsprintf.c]
	Altered WPRINTF_ParseFormatA/W to treat invalid format chars
	as normal output, too.

	* [msdos/dpmi.c]
	Implemented "Allocate/Free real mode callback" (0x0303/0x0304).
	Cross your fingers if you need to use it ;) (completely untested)
	Implemented "Call real mode proc with far return" (0x0301, tested).

	* [msdos/int21.c]
	Fixed ioctlGenericBlkDevReq/0x60.

	* [relay32/dplayx.spec] [relay32/builtin32.c] [relay32/Makefile.in]
	Added built-in DPLAYX.DLL. 

	* [windows/win.c]
	Fixed GetWindowWord()/GWW_HWNDPARENT to return the window's owner
	if it has no parent (SDK).

Sat Apr 25 15:09:53 1998  M.T.Fortescue  <mark@mtfhpc.demon.co.uk>

	* [debugger/db_disasm.c]
	Fixed disassemble bug for no-display option and 'lock',
	'repne' and 'repe' prefixes.

	* [debugger/registers.c]
	Added textual flag description output on 'info regs'.

Sat Apr 25 14:18:26 1998  Matthew Becker <mbecker@glasscity.net>

	* [*/*.c]
	Added stubs and/or documentation for the following functions: 
	LookupPrivilegeValue, OpenService, ControlService, RegGetKeySecurity, 
	StartService, SetComputerName, DeleteService, CloseServiceHandle, 
	OpenProcessToken, OpenSCManager, DeregisterEventSource, 
	WaitForDebugEvent, WaitForInputIdle, RegisterEventSource,
	SetDebugErrorLevel, SetConsoleCursorPosition, ChoosePixelFormat,
	SetPixelFormat, GetPixelFormat, DescribePixelFormat, SwapBuffers,
	PolyBezier, AbortPath, DestroyAcceleratorTable, HeapWalk,
	DdeInitialize, DdeUninitialize, DdeConnectList, DdeDisconnectList,
	DdeCreateStringHandle, DdePostAdvise, DdeGetData, DdeNameService,
	DdeGetLastError, WNetGetDirectoryType, EnumPrinters, RegFlushKey,
	RegGetKeySecurity, DllGetClassObject, DllCanUnloadNow, CreateBitmap,
	CreateCompatibleBitmap, CreateBitmapIndirect, GetBitmapBits,
	SetBitmapBits, LoadImage, CopyImage, LoadBitmap, DrawIcon,
	CreateDiscardableBitmap, SetDIBits, GetCharABCWidths, LoadTypeLib,
	SetConsoleCtrlHandler, CreateConsoleScreenBuffer, ReadConsoleInput,
	GetConsoleCursorInfo, SetConsoleCursorInfo, SetConsoleWindowInfo,
	SetConsoleTextAttribute, SetConsoleScreenBufferSize,
	FillConsoleOutputCharacter, FillConsoleOutputAttribute,
	CreateMailslot, GetMailslotInfo, GetCompressedFileSize,
	GetProcessWindowStation, GetThreadDesktop, SetDebugErrorLevel,
	WaitForDebugEvent, SetComputerName, CreateMDIWindow.

Thu Apr 23 23:54:04 1998  Douglas Ridgway  <ridgway@winehq.com>

	* [include/windows.h] [objects/enhmetafile.c] [relay32/gdi32.spec]
	Implement CopyEnhMetaFile, Get/SetEnhMetaFileBits, other fixes.

	* [include/windows.h] [objects/metafile.c] [relay32/gdi32.spec]
	32-bit metafile fixes, implement EnumMetaFile32, GetMetaFileBitsEx.

	* [objects/font.c] [graphics/x11drv/xfont.c] [graphics/x11drv/text.c]
	Some rotated text support for X11R6 displays.

	* [win32/newfns.c] [ole/ole2nls.c]
	Moved GetNumberFormat32A.

Wed Apr 22 17:38:20 1998  David Lee Lambert <lamber45@egr.msu.edu>

	* [ole/ole2nls.c] [misc/network.c]
	Changed some function documentation to the new style.

	* [misc/network.c] [include/windows.h] [if1632/user.spec]
	  [relay32/mpr.spec] [misc/mpr.c]
	Added stubs for some Win32 network functions;  renamed some 
	16-bit ones with 32-bit counterparts,  as well as
	WNetGetDirectoryType;  moved the stubs in misc/mpr.c (three of
	them!) to misc/network.c.

	* [ole/compobj.c] [ole/storage.c] [ole/ole2disp.c] 
	  [ole/ole2nls.c] [ole/folders.c] [ole/moniker.c] [ole/ole2.c]
	  [graphics/fontengine.c] [graphics/ddraw.c] [graphics/env.c]
	  [graphics/driver.c] [graphics/escape.c]
	Changed fprintf's to proper debug-macros.

	* [include/winnls.h]
	Added some flags (for internal use).

	* [ole/ole2nls.c] 
	Added the Unicode core function, and worked out a way to hide
	the commonality of the core.

	* [relay32/kernel32.spec]
	Added support for GetDate/Time32A/W.

Wed Apr 22 09:16:03 1998  Gordon Chaffee  <chaffee@cs.berkeley.edu>

	* [win32/code_page.c]
	Fixed problem with MultiByteToWideChar that was introduced in
	last release.  Made MultiByteToWideChar more compatible with Win32.

	* [graphics/x11drv/graphics.c]
	Fixed problem with drawing arcs.

Tue Apr 21 11:24:58 1998  Constantine Sapuntzakis  <csapuntz@tma-1.lcs.mit.edu>

	*  [ole/ole2nls.c]
	Move stuff from 0x409 case to Lang_En. 

	*  [relay32/user32.spec] [windows/winpos.c]
	Added stubs for GetWindowRgn32 and SetWindowRgn32. Makes Office
	Paperclip happy.

Tue Apr 21 11:16:16 1998  Constantine Sapuntzakis  <csapuntz@tma-1.lcs.mit.edu>

	*  [loader/pe_image.c]
	If image is relocated, TLS addresses need to be adjusted.

	* [debugger/*.c]
	Generalized tests for 32-bit segments.

Tue Apr 21 02:04:59 1998  James Juran  <jrj120@psu.edu>
	
	* [misc/*.c] [miscemu/*.c] [msdos/*.c] [if1632/*.c] 
	  [include/*.h] [loader/*.c] [memory/*.c] [multimedia/*.c] 
	  [objects/*.c]
	Almost all fprintf statements converted to appropriate 
	debug messages.

	* [README]
	Updated "GETTING MORE INFORMATION" section to include WineHQ.

	* [documentation/debugger]
	Fixed typo.

	* [windows/defwnd.c]
	Added function documentation.

Sun Apr 19 16:30:58 1998  Marcus Meissner <marcus@mud.de>

	* [Make.rules.in]
	Added lint target (using lclint).

	* [relay32/oleaut32.spec][relay32/Makefile.in][ole/typelib.c]
	  [ole/ole2disp.c]
	Added oleaut32 spec, added some SysString functions.

	* [if1632/signal.c]
	Added printing of faultaddress in Linux (using CR2 debug register).

	* [configure.in]
	Added <sys/types.h> for statfs checks.

	* [loader/*.c][debugger/break.c][debugger/hash.c]
	Started to split win32/win16 module handling, preparing support
	for other binary formats (like ELF).

Sat Apr 18 10:07:41 1998  Rein Klazes <rklazes@casema.net>

	* [misc/registry.c]
	Fixed a bug that made RegQueryValuexxx returning
	incorrect registry values.

Fri Apr 17 22:59:22 1998  Alexander V. Lukyanov <lav@long.yar.ru>

	* [misc/lstr.c]
	FormatMessage32*: remove linefeed when nolinefeed set;
	check for target underflow.

Fri Apr 17 00:38:14 1998  Alexander V. Lukyanov <lav@long.yar.ru>

	* [misc/crtdll.c]
	Implement xlat_file_ptr for CRT stdin/stdout/stderr address
	translation.

Wed Apr 15 20:43:56 1998  Jim Peterson <jspeter@birch.ee.vt.edu>

	* [controls/menu.c]
	Added 'odaction' parameter to MENU_DrawMenuItem() and redirected
	WM_DRAWITEM messages to GetWindow(hwnd,GW_OWNER).

Tue Apr 14 16:17:55 1998  Berend Reitsma <berend@united-info.com>

	* [graphics/metafiledrv/init.c]	[graphics/painting.c] 
	  [graphics/win16drv/init.c] [graphics/x11drv/graphics.c]
	  [graphics/x11drv/init.c] [include/gdi.h] [include/x11drv.h]
	  [relay32/gdi32.spec]
	Added PolyPolyline routine.

	* [windows/winproc.c]
	Changed WINPROC_GetProc() to return proc instead of &(jmp proc).
1998-05-03 19:01:20 +00:00

712 lines
24 KiB
C

/*
* NE segment loading
*
* Copyright 1993 Robert J. Amstadt
* Copyright 1995 Alexandre Julliard
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include "neexe.h"
#include "windows.h"
#include "global.h"
#include "task.h"
#include "selectors.h"
#include "callback.h"
#include "file.h"
#include "module.h"
#include "stackframe.h"
#include "debug.h"
#include "xmalloc.h"
/***********************************************************************
* NE_GetRelocAddrName
*/
static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
{
switch(addr_type & 0x7f)
{
case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
}
return "???";
}
/***********************************************************************
* NE_LoadSegment
*/
BOOL32 NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
{
SEGTABLEENTRY *pSegTable, *pSeg;
WORD *pModuleTable;
WORD count, i, offset, next_offset;
HMODULE16 module;
FARPROC16 address = 0;
int fd;
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;
pModuleTable = NE_MODULE_TABLE( pModule );
if (!pSeg->filepos) return TRUE; /* No file image, just return */
fd = MODULE_OpenFile( pModule->self );
TRACE(module, "Loading segment %d, selector=%04x, flags=%04x\n",
segnum, pSeg->selector, pSeg->flags );
lseek( fd, pSeg->filepos << pModule->alignment, SEEK_SET );
if (pSeg->size) size = pSeg->size;
else if (pSeg->minsize) size = pSeg->minsize;
else size = 0x10000;
mem = GlobalLock16(pSeg->selector);
if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
{
/* Implement self loading segments */
SELFLOADHEADER *selfloadheader;
STACK16FRAME *stack16Top;
DWORD oldstack;
WORD oldselector, newselector;
THDB *thdb = THREAD_Current();
HFILE32 hf = FILE_DupUnixHandle( fd );
selfloadheader = (SELFLOADHEADER *)
PTR_SEG_OFF_TO_LIN(pSegTable->selector,0);
oldstack = thdb->cur_stack;
oldselector = pSeg->selector;
thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
0xff00 - sizeof(*stack16Top));
stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
stack16Top->frame32 = 0;
stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
stack16Top->entry_point = 0;
stack16Top->entry_ip = 0;
stack16Top->entry_cs = 0;
stack16Top->bp = 0;
stack16Top->ip = 0;
stack16Top->cs = 0;
newselector = Callbacks->CallLoadAppSegProc(selfloadheader->LoadAppSeg,
pModule->self, hf, segnum );
_lclose32( hf );
if (newselector != oldselector) {
/* Self loaders like creating their own selectors;
* they love asking for trouble to Wine developers
*/
if (segnum == pModule->dgroup) {
memcpy(PTR_SEG_OFF_TO_LIN(oldselector,0),
PTR_SEG_OFF_TO_LIN(newselector,0),
pSeg->minsize ? pSeg->minsize : 0x10000);
FreeSelector(newselector);
pSeg->selector = oldselector;
fprintf(stderr, "A new selector was allocated for the dgroup segment\n"
"Old selector is %d, new one is %d", oldselector, newselector);
} else {
FreeSelector(pSeg->selector);
pSeg->selector = newselector;
}
}
thdb->cur_stack = oldstack;
}
else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
read(fd, mem, 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. If you have any doc please either send
it to me or fix the code yourself. gfm@werple.mira.net.au
*/
char* buff = xmalloc(size);
char* curr = buff;
read(fd, buff, size);
while(curr < buff + size) {
unsigned int rept = *((short*) curr)++;
unsigned int len = *((short*) curr)++;
for(; rept > 0; rept--) {
char* bytes = curr;
unsigned int byte;
for(byte = 0; byte < len; byte++)
*mem++ = *bytes++;
}
curr += len;
}
free(buff);
}
pSeg->flags |= NE_SEGFLAGS_LOADED;
if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
return TRUE; /* No relocation data, we are done */
read( fd, &count, sizeof(count) );
if (!count) return TRUE;
TRACE(fixup, "Fixups for %.*s, segment %d, selector %04x\n",
*((BYTE *)pModule + pModule->name_table),
(char *)pModule + pModule->name_table + 1,
segnum, pSeg->selector );
TRACE(segment, "Fixups for %.*s, segment %d, selector %04x\n",
*((BYTE *)pModule + pModule->name_table),
(char *)pModule + pModule->name_table + 1,
segnum, pSeg->selector );
reloc_entries = (struct relocation_entry_s *)xmalloc(count * sizeof(struct relocation_entry_s));
if (read( fd, reloc_entries, count * sizeof(struct relocation_entry_s)) !=
count * sizeof(struct relocation_entry_s))
{
WARN(fixup, "Unable to read relocation information\n" );
return FALSE;
}
/*
* 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.
*/
/* 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:
module = pModuleTable[rep->target1-1];
ordinal = rep->target2;
address = NE_GetEntryPoint( module, ordinal );
if (!address)
{
NE_MODULE *pTarget = MODULE_GetPtr16( module );
if (!pTarget)
fprintf( stderr, "Module not found: %04x, reference %d of module %*.*s\n",
module, rep->target1,
*((BYTE *)pModule + pModule->name_table),
*((BYTE *)pModule + pModule->name_table),
(char *)pModule + pModule->name_table + 1 );
else
fprintf( stderr, "Warning: no handler for %.*s.%d, setting to 0:0\n",
*((BYTE *)pTarget + pTarget->name_table),
(char *)pTarget + pTarget->name_table + 1,
ordinal );
}
if (TRACE_ON(fixup))
{
NE_MODULE *pTarget = MODULE_GetPtr16( module );
TRACE( fixup, "%d: %.*s.%d=%04x:%04x %s\n", i + 1,
*((BYTE *)pTarget + pTarget->name_table),
(char *)pTarget + pTarget->name_table + 1,
ordinal, HIWORD(address), LOWORD(address),
NE_GetRelocAddrName( rep->address_type, additive ) );
}
break;
case NE_RELTYPE_NAME:
module = pModuleTable[rep->target1-1];
func_name = (char *)pModule + pModule->import_table + rep->target2;
memcpy( buffer, func_name+1, *func_name );
buffer[*func_name] = '\0';
func_name = buffer;
ordinal = NE_GetOrdinal( module, func_name );
address = NE_GetEntryPoint( module, ordinal );
if (ERR_ON(fixup) && !address)
{
NE_MODULE *pTarget = MODULE_GetPtr16( module );
ERR(fixup, "Warning: no handler for %.*s.%s, setting to 0:0\n",
*((BYTE *)pTarget + pTarget->name_table),
(char *)pTarget + pTarget->name_table + 1, func_name );
}
if (TRACE_ON(fixup))
{
NE_MODULE *pTarget = MODULE_GetPtr16( module );
TRACE( fixup, "%d: %.*s.%s=%04x:%04x %s\n", i + 1,
*((BYTE *)pTarget + pTarget->name_table),
(char *)pTarget + pTarget->name_table + 1,
func_name, HIWORD(address), LOWORD(address),
NE_GetRelocAddrName( rep->address_type, additive ) );
}
break;
case NE_RELTYPE_INTERNAL:
if ((rep->target1 & 0xff) == 0xff)
{
address = NE_GetEntryPoint( pModule->self, rep->target2 );
}
else
{
address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( pSegTable[rep->target1-1].selector, rep->target2 );
}
TRACE( fixup,"%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( fixup, "%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;
/* Apparently, high bit of address_type is sometimes set; */
/* we ignore it for now */
if (rep->address_type > NE_RADDR_OFFSET32)
ERR( fixup, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
MODULE_GetModuleName(pModule->self), rep->address_type );
if (additive)
{
sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
TRACE( fixup," %04x:%04x\n", offset, *sp );
switch (rep->address_type & 0x7f)
{
case NE_RADDR_LOWBYTE:
*(BYTE *)sp += LOBYTE((int)address);
break;
case NE_RADDR_OFFSET16:
*sp += LOWORD(address);
break;
case NE_RADDR_POINTER32:
*sp += LOWORD(address);
*(sp+1) = HIWORD(address);
break;
case NE_RADDR_SELECTOR:
/* Borland creates additive records with offset zero. Strange, but OK */
if (*sp)
ERR(fixup,"Additive selector to %04x.Please report\n",*sp);
else
*sp = HIWORD(address);
break;
default:
goto unknown;
}
}
else /* non-additive fixup */
{
do
{
sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
next_offset = *sp;
TRACE( fixup," %04x:%04x\n", offset, *sp );
switch (rep->address_type & 0x7f)
{
case NE_RADDR_LOWBYTE:
*(BYTE *)sp = LOBYTE((int)address);
break;
case NE_RADDR_OFFSET16:
*sp = LOWORD(address);
break;
case NE_RADDR_POINTER32:
*(FARPROC16 *)sp = address;
break;
case NE_RADDR_SELECTOR:
*sp = SELECTOROF(address);
break;
default:
goto unknown;
}
if (next_offset == offset) break; /* avoid infinite loop */
if (next_offset >= GlobalSize16(pSeg->selector)) break;
offset = next_offset;
} while (offset && (offset != 0xffff));
}
}
free(reloc_entries);
return TRUE;
unknown:
WARN(fixup, "WARNING: %d: unknown ADDR TYPE %d, "
"TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
i + 1, rep->address_type, rep->relocation_type,
rep->offset, rep->target1, rep->target2);
free(reloc_entries);
return FALSE;
}
/***********************************************************************
* NE_LoadAllSegments
*/
BOOL32 NE_LoadAllSegments( NE_MODULE *pModule )
{
int i;
if (pModule->flags & NE_FFLAGS_SELFLOAD)
{
HFILE32 hf;
/* Handle self loading modules */
SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
SELFLOADHEADER *selfloadheader;
STACK16FRAME *stack16Top;
THDB *thdb = THREAD_Current();
HMODULE16 hselfload = GetModuleHandle16("WPROCS");
DWORD oldstack;
WORD saved_dgroup = pSegTable[pModule->dgroup - 1].selector;
TRACE(module, "%.*s is a self-loading module!\n",
*((BYTE*)pModule + pModule->name_table),
(char *)pModule + pModule->name_table + 1);
if (!NE_LoadSegment( pModule, 1 )) return FALSE;
selfloadheader = (SELFLOADHEADER *)
PTR_SEG_OFF_TO_LIN(pSegTable->selector, 0);
selfloadheader->EntryAddrProc = NE_GetEntryPoint(hselfload,27);
selfloadheader->MyAlloc = NE_GetEntryPoint(hselfload,28);
selfloadheader->SetOwner = NE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
pModule->self_loading_sel = GlobalHandleToSel(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
oldstack = thdb->cur_stack;
thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
0xff00 - sizeof(*stack16Top) );
stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
stack16Top->frame32 = 0;
stack16Top->ebp = 0;
stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
stack16Top->entry_point = 0;
stack16Top->entry_ip = 0;
stack16Top->entry_cs = 0;
stack16Top->bp = 0;
stack16Top->ip = 0;
stack16Top->cs = 0;
hf = FILE_DupUnixHandle( MODULE_OpenFile( pModule->self ) );
Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self, hf);
_lclose32(hf);
/* some BootApp procs overwrite the selector of dgroup */
pSegTable[pModule->dgroup - 1].selector = saved_dgroup;
thdb->cur_stack = oldstack;
for (i = 2; i <= pModule->seg_count; i++)
if (!NE_LoadSegment( pModule, i )) return FALSE;
}
else
{
for (i = 1; i <= pModule->seg_count; i++)
if (!NE_LoadSegment( pModule, i )) return FALSE;
}
return TRUE;
}
/***********************************************************************
* NE_FixupPrologs
*
* Fixup the exported functions prologs.
*/
void NE_FixupPrologs( NE_MODULE *pModule )
{
SEGTABLEENTRY *pSegTable;
WORD dgroup = 0;
WORD sel;
BYTE *p, *fixup_ptr, count;
dbg_decl_str(module, 512);
pSegTable = NE_SEG_TABLE(pModule);
if (pModule->flags & NE_FFLAGS_SINGLEDATA)
dgroup = pSegTable[pModule->dgroup-1].selector;
TRACE(module, "(%04x)\n", pModule->self );
p = (BYTE *)pModule + pModule->entry_table;
while (*p)
{
if (p[1] == 0) /* Unused entry */
{
p += 2; /* Skip it */
continue;
}
if (p[1] == 0xfe) /* Constant entry */
{
p += 2 + *p * 3; /* Skip it */
continue;
}
/* Now fixup the entries of this bundle */
count = *p;
sel = p[1];
p += 2;
while (count-- > 0)
{
dbg_reset_str(module);
dsprintf(module,"Flags: %04x, sel %02x ", *p, sel);
/* According to the output generated by TDUMP, the flags mean:
* 0x0001 function is exported
* 0x0002 Single data (seems to occur only in DLLs)
*/
if (sel == 0xff) { /* moveable */
dsprintf(module, "(%02x) o %04x", p[3], *(WORD *)(p+4) );
fixup_ptr = (char *)GET_SEL_BASE(pSegTable[p[3]-1].selector) + *(WORD *)(p + 4);
} else { /* fixed */
dsprintf(module, "offset %04x", *(WORD *)(p+1) );
fixup_ptr = (char *)GET_SEL_BASE(pSegTable[sel-1].selector) +
*(WORD *)(p + 1);
}
TRACE(module, "%s Signature: %02x %02x %02x,ff %x\n",
dbg_str(module), fixup_ptr[0], fixup_ptr[1],
fixup_ptr[2], pModule->flags );
if (*p & 0x0001)
{
/* Verify the signature */
if (((fixup_ptr[0] == 0x1e && fixup_ptr[1] == 0x58)
|| (fixup_ptr[0] == 0x8c && fixup_ptr[1] == 0xd8))
&& fixup_ptr[2] == 0x90)
{
if (*p & 0x0002)
{
if (pModule->flags & NE_FFLAGS_MULTIPLEDATA)
{
/* can this happen? */
fprintf( stderr, "FixupPrologs got confused\n" );
}
else if (pModule->flags & NE_FFLAGS_SINGLEDATA)
{
*fixup_ptr = 0xb8; /* MOV AX, */
*(WORD *)(fixup_ptr+1) = dgroup;
}
}
else
{
if (pModule->flags & NE_FFLAGS_MULTIPLEDATA) {
fixup_ptr[0] = 0x90; /* non-library: NOPs */
fixup_ptr[1] = 0x90;
fixup_ptr[2] = 0x90;
}
}
} else {
WARN(fixup, "Unknown signature\n" );
}
}
else
TRACE(module,"\n");
p += (sel == 0xff) ? 6 : 3;
}
}
}
/***********************************************************************
* NE_InitDLL
*
* Call the DLL initialization code
*/
static BOOL32 NE_InitDLL( TDB* pTask, HMODULE16 hModule )
{
NE_MODULE *pModule;
SEGTABLEENTRY *pSegTable;
CONTEXT context;
/* Registers at initialization must be:
* cx heap size
* di library instance
* ds data segment if any
* es:si command line (always 0)
*/
if (!(pModule = MODULE_GetPtr16( hModule ))) return FALSE;
pSegTable = NE_SEG_TABLE( pModule );
if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
(pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
/* Call USER signal handler. This is necessary to install a
* proper loader for HICON and HCURSOR resources that this DLL
* may contain. InitApp() does this for task modules. */
if (pTask && pTask->userhandler)
{
pTask->userhandler( hModule, USIG_DLL_LOAD, 0, pTask->hInstance,
pTask->hQueue );
}
if (!pModule->cs) return TRUE; /* no initialization code */
memset( &context, 0, sizeof(context) );
if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
{
if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
{
/* Not SINGLEDATA */
fprintf(stderr, "Library is not marked SINGLEDATA\n");
exit(1);
}
else /* DATA NONE DLL */
{
DS_reg(&context) = 0;
ECX_reg(&context) = 0;
}
}
else /* DATA SINGLE DLL */
{
if (pModule->dgroup) {
DS_reg(&context) = pSegTable[pModule->dgroup-1].selector;
ECX_reg(&context) = pModule->heap_size;
}
else /* hmm, DLL has no dgroup,
but why has it NE_FFLAGS_SINGLEDATA set ?
Buggy DLL compiler ? */
{
DS_reg(&context) = 0;
ECX_reg(&context) = 0;
}
}
CS_reg(&context) = pSegTable[pModule->cs-1].selector;
EIP_reg(&context) = pModule->ip;
EBP_reg(&context) = OFFSETOF(THREAD_Current()->cur_stack)
+ (WORD)&((STACK16FRAME*)0)->bp;
EDI_reg(&context) = DS_reg(&context) ? DS_reg(&context) : hModule;
pModule->cs = 0; /* Don't initialize it twice */
TRACE(dll, "Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
CS_reg(&context), IP_reg(&context), DS_reg(&context),
DI_reg(&context), CX_reg(&context) );
Callbacks->CallRegisterShortProc( &context, 0 );
return TRUE;
}
/***********************************************************************
* NE_InitializeDLLs
*
* Recursively initialize all DLLs (according to the order in which
* they where loaded).
*/
void NE_InitializeDLLs( HMODULE16 hModule )
{
TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
NE_MODULE *pModule;
HMODULE16 *pDLL;
if (!(pModule = MODULE_GetPtr16( hModule ))) return;
if (pModule->flags & NE_FFLAGS_WIN32) return;
if (pModule->dlls_to_init)
{
HGLOBAL16 to_init = pModule->dlls_to_init;
pModule->dlls_to_init = 0;
for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
{
NE_InitializeDLLs( *pDLL );
}
GlobalFree16( to_init );
}
NE_InitDLL( pTask, hModule );
}
/***********************************************************************
* PatchCodeHandle
*
* Needed for self-loading modules.
*/
/* It does nothing */
void WINAPI PatchCodeHandle(HANDLE16 hSel)
{
fprintf(stderr,"PatchCodeHandle(%04x),stub!\n",hSel);
}
/***********************************************************************
* NE_Ne2MemFlags
*
* This function translates NE segment flags to GlobalAlloc flags
*/
static WORD NE_Ne2MemFlags(WORD flags)
{
WORD memflags = 0;
#if 0
if (flags & NE_SEGFLAGS_DISCARDABLE)
memflags |= GMEM_DISCARDABLE;
if (flags & NE_SEGFLAGS_MOVEABLE ||
( ! (flags & NE_SEGFLAGS_DATA) &&
! (flags & NE_SEGFLAGS_LOADED) &&
! (flags & NE_SEGFLAGS_ALLOCATED)
)
)
memflags |= GMEM_MOVEABLE;
memflags |= GMEM_ZEROINIT;
#else
memflags = GMEM_ZEROINIT | GMEM_FIXED;
return memflags;
#endif
}
/***********************************************************************
* NE_AllocateSegment (WPROCS.26)
*/
DWORD WINAPI NE_AllocateSegment( WORD wFlags, WORD wSize, WORD wElem )
{
WORD size = wSize << wElem;
HANDLE16 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
return MAKELONG( hMem, GlobalHandleToSel(hMem) );
}
/***********************************************************************
* NE_CreateSegments
*/
BOOL32 NE_CreateSegments( HMODULE16 hModule )
{
SEGTABLEENTRY *pSegment;
NE_MODULE *pModule;
int i, minsize;
if (!(pModule = MODULE_GetPtr16( hModule ))) return FALSE;
assert( !(pModule->flags & NE_FFLAGS_WIN32) );
pSegment = NE_SEG_TABLE( pModule );
for (i = 1; i <= pModule->seg_count; i++, pSegment++)
{
minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
if (i == pModule->ss) minsize += pModule->stack_size;
/* The DGROUP is allocated by MODULE_CreateInstance */
if (i == pModule->dgroup) continue;
pSegment->selector = GLOBAL_Alloc( NE_Ne2MemFlags(pSegment->flags),
minsize, hModule,
!(pSegment->flags & NE_SEGFLAGS_DATA),
FALSE,
FALSE /*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
if (!pSegment->selector) return FALSE;
}
pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
(pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
return TRUE;
}