1
0
Fork 0
mirror of synced 2025-03-07 03:53:26 +01:00
wine/loader/ne/segment.c
Alexandre Julliard dadf78ffa9 Release 980517
Sun May 17 16:23:56 1998  Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>

	* [file/profile.c]
	Fix the return value of PROFILE_GetSection

	* [misc/crtdll.c]
	Do _getdrive, fix _chdrive.

	* [misc/commdlg.c]
	First cut at ChooseColor[WA].

	* [misc/network.c]
	Do something sensible for WNetGetDirectoryType16.

Sun May 17 10:21:35 1998  Andreas Mohr <100.30936@germany.net>

	* [controls/menu.c]
	Fixed disabled sub menus with MF_BYPOSITION that were not disabled.

	* [misc/crtdll.c] [relay32/crtdll.spec] [include/winerror.h]
	Implemented fscanf, fsetpos, _access, _fpreset (thanks to Uwe Bonnes),
	and _ltoa. 

	* [loader/task.c]
	MakeProcInstance: must use CURRENT_DS if hInst == NULL.

	* [misc/shell.c]
	SHELL_GetResourceTable, InternalExtractIcon: fixed broken .ICO handling

	* [windows/winpos.c]
	DeferWindowPos: removed "same parent" requirement.
	Which doc states that this is required ?

Sat May 16 20:08:11 1998  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [loader/module.c] [loader/ne/module.c]
	More NE module cleanups.

	* [loader/task.c]
	Fixed SwitchStackBack().

Fri May 15 10:04:27 1998  Marcus Meissner <marcus@jet.franken.de>

	* [configure.in][inlcude/acconfig.h]
	Fixed broken OSS check, added check for working sigaltstack,
	fixed broken statfs checks on some linux systems.

	* [files/directory.c][loader/pe_image.c][relay32/builtin.c]
	  [loader/module.c]
	Added handling of win32 module pathnames.

	* [relay32/wnaspi32.spec]
	New file.

	* [misc/lzexpand.c]
	LZCopy auto-decompresses LZ compressed files, even if they are not
	specially flagged. Fixes some InstallShield problems.

	* [misc/registry.c]
	Some fixes for RegQueryInfoKey (reference program monkey.exe
	from Win32 SDK works now better). Probably still has faults.

Fri May 15 08:58:58 1998  Martin Boehme <boehme@informatik.mu-luebeck.de>

	* [graphics/mapping.c] [include/dc.h] [include/gdi.h] [objects/dc.c]
	Reworked the way world transformations and mapping modes are handled
	so that both of these transformations can be computed in a single
	step.

	* [graphics/painting.c] [graphics/path.c] [include/path.h]
	More GDI path support.

	* [graphics/x11drv/graphics.c]
	Fixed the return value of GRAPH_DrawArc for the zero height /
	zero width case to reflect Windows' behaviour.

	* [include/windows.h] [relay32/gdi32.spec] [objects/dc.c]
	Implemented ModifyWorldTransform and CombineTransform.

Tue May 14 18:03:46 1998  Eric Kohl <ekohl@abo.rhein-zeitung.de>

	* [controls/commctrl.c][relay32/comctl32.spec]
	  [controls/*.c][include/*.h]
	Implemented InitCommonControlsEx (dll version 4.72 compatible).
	InitCommonControls calls ImageCommonControlsEx.
	Registering code of the common controls had to be changed
	(see XXXX_Register functions).

	* [controls/status.c][include/commctrl.h][include/status.h]
	Implemented most new features and fixed the look and feel.

	* [contols/commctrl.c][include/commctrl.h][relay32/comctl32.spec]
	Implemented MenuHelp (incomplete).

	* [controls/status.c][controls/progress.c]
	Changed allocation strategy for control specific memory.

	* [controls/header.c][include/header.h][include/commctrl.h]
	First implementation of header control.

	* [windows/defwnd.c][windows/syscolors.c]
	Fixed default control colors for Win95 look.

	* [windows/nonclient.c]
	Fixed off by one error for Win95 look. Top border of child windows
	should be visible.

	* [misc/imagelist.h]
	Improved documentation and fixed some bugs.

Thu May 14 15:42:21 1998  Robert Wilhelm  <robert@physiol.med.tu-muenchen.de>

	* [relay32/crtdll.spec]
	Added hypot,j0,j1,jn and ceil.

Wed May 13 19:10:10 1998  Pascal Cuoq <pcuoq@ens-lyon.fr>

	* [controls/listbox.c]
	Item height is now exactly font height.
	Wine listboxes now behave like Windows' when they are 
	created without WS_VSCROLL but the program subsequently 
	calls ShowScrollBar or SetScrollInfo.

Wed May 13 18:33:01 1998  Ulrich Weigand <weigand@informatik.uni-erlangen.de>

	* [relay32/relay386.c]
	Restore ES also in the non-debug case.

	* [windows/event.c]
	Bugfix: Blocking TSXNextEvent could deadlock Wine.

	* [win32/process.c] [windows/message.c]
	Silly stubs for MsgWaitForMultipleObjects / PostThreadMessage
	that make some programs run better.

	* [windows/winproc.c]
	WINPROC_MapMsg32Ato16/16To32A: added WM_NOTIFY.  

        * [win32/kernel32.c]
	Added 16->32 thunking and improved 32->16 thunking functions.

	* [tools/build.c]
	Added new variant of CallFrom16 stub for use with Win95 thunks.

	* [if1632/kernel.spec] [if1632/builtin.c] [win32/kernel32.c]
	Added a few undocumented KERNEL functions.

	* [loader/ne/module.c] [loader/ne/segment.c]
	Call DllEntryPoint for 16-bit DLLs with subsystem >= 4.0.

	* [win32/kernel32.spec] [win32/wow32.spec] [win32/ordinals.c]
	Use names from the Oct 94 beta release for undoc. functions.

Wed May 13 14:18:26 1998  Matthew Becker <mbecker@glasscity.net>

	* [misc/registry.c]
	Code cleanup.

	* [misc/cpu.c]
	Commented out the registry puts temporarily.

	* [programs/regtest/*]
	New registry testing program.

Tue May 12 22:54:03 1998  Michael Mess <michael@kawo2.rwth-aachen.de>

	* [multimedia/audio.c]
	ioctl's do not commute in /dev/dsp initialization.

Tue May 12 20:11:42 1998  Karl Garrison <karlos@eznet.net>

	* [win32/console.c]
	Implemented SetConsoleTextAttribute, FillConsoleOutputCharacter.
	Improved cursor positioning.
	This allows for text colors in an xterm, rxvt, or console.

Tue May 12 17:57:52 1998  Petter Reinholdtsen <pere@td.org.uit.no>

	* [Makefile.in]
	Create prefix/{bin|lib} directories if missing during install.

Sun May 10 19:37:51 1998  Jan Willamowius <jan@janhh.shnet.org>

	* [multimedia/mmio.c]
	Have mmioSetBuffer return success (0), so Corel Draw 4
	keeps working. (IO is still unbuffered)

Wed May  6 16:57:55 1998  James Juran <jrj120@psu.edu>

        * [Makefile.in] [Make.rules.in]
	Changed "make clean" to remove `textedit` backup files (*%)

	* [controls/menu.c][graphics/x11drv/xfont.c][include/libres.h]
	  [loader/main.c][loader/ne/module.c][scheduler/synchro.c]
	  [win32/time.c][windows/winpos.c][include/windows.h]
	Fixed miscellaneous compilation warnings.

	* [misc/main.c][miscemu/main.c][include/main.h]
	Moved prototypes to new include file main.h, various cleanups.

Tue May  5 21:05:06 1998  Morten Welinder  <terra@diku.dk>

	* [misc/winsock.c]
	Don't refer to __FreeBSD__ when HAVE_STRERROR is meant.

	* [misc/debugstr.c]
	For debug_dumpstrSend, send strings to stderr.

Tue May  5 21:47:40 1998  Huw D M Davies <h.davies1@physics.oxford.ac.uk>

	* [objects/region.c]
	Fix for REGION_RegionOp() if newReg is one of the source regions.

Tue May  5 18:27:32 1998  Jim Peterson <jspeter@roanoke.infi.net>

	* [misc/main.c]
	Add '-h/-help' option and print WINE_RELEASE_INFO with usage message.

	* [misc/spy.c]
	Realign trace messages.

Tue May  5 15:46:47 1998  Donnie V. Savage <dsavage@cisco.com>

	* [graphics/ddraw.c]
	Fixed compile warnings

	* [misc/winsock.c]
	Warnings should not be errors.

Tue May  5 13:40:42 1998  Jim Peterson <jspeter@roanoke.infi.net>

	* [*/*]
	Remove many warnings through explicit casts, added #include's,
	and corrected printf formats.

Tue May  5 05:18:12 1998  Insomnia (Stea Greene) <insomnia@core.binghamton.edu>

	* [graphics/ddraw.c]
	Kept unchanged portion of old palette when changing only a few
	palette entries.  Really should only deallocate the changed cells.
	This make StarCraft work almost perfectly (sound overflows still
	cause static).

Mon May  4 15:04:57 1998  Alexander V. Lukyanov <lav@long.yar.ru>

	* [misc/lstr.c]
	FormatMessage: terminate string on %0, undo linefeed strip.
1998-05-17 17:13:43 +00:00

802 lines
26 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 = NE_OpenFile( pModule );
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;
TRACE(module, "New selector allocated for dgroup segment:Old=%d,New=%d\n",
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 = NE_GetPtr( module );
if (!pTarget)
WARN(module, "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
WARN(module, "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 = NE_GetPtr( 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 = NE_GetPtr( 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 = NE_GetPtr( 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)
{
char module[10];
GetModuleName( pModule->self, module, sizeof(module) );
ERR( fixup, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
module, 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( NE_OpenFile( pModule ) );
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? */
ERR(fixup, "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, 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)
*/
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( pModule->self, 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 */
ERR(dll, "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) : pModule->self;
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_CallDllEntryPoint
*
* Call the DllEntryPoint of DLLs with subsystem >= 4.0
*/
static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
{
FARPROC16 entryPoint;
WORD ordinal;
CONTEXT context;
THDB *thdb = THREAD_Current();
LPBYTE stack = (LPBYTE)THREAD_STACK16(thdb);
if (pModule->expected_version < 0x0400) return;
if (!(ordinal = NE_GetOrdinal( pModule->self, "DllEntryPoint" ))) return;
if (!(entryPoint = NE_GetEntryPoint( pModule->self, ordinal ))) return;
memset( &context, 0, sizeof(context) );
CS_reg(&context) = HIWORD(entryPoint);
IP_reg(&context) = LOWORD(entryPoint);
EBP_reg(&context) = OFFSETOF( thdb->cur_stack )
+ (WORD)&((STACK16FRAME*)0)->bp;
*(DWORD *)(stack - 4) = dwReason; /* dwReason */
*(WORD *) (stack - 6) = pModule->self; /* hInst */
*(WORD *) (stack - 8) = 0; /* wDS */
*(WORD *) (stack - 10) = 0; /* wHeapSize */
*(DWORD *)(stack - 14) = 0; /* dwReserved1 */
*(WORD *) (stack - 16) = 0; /* wReserved2 */
TRACE(dll, "Calling DllEntryPoint, cs:ip=%04lx:%04x\n",
CS_reg(&context), IP_reg(&context));
Callbacks->CallRegisterShortProc( &context, 16 );
}
/***********************************************************************
* 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 = NE_GetPtr( hModule ))) return;
assert( !(pModule->flags & NE_FFLAGS_WIN32) );
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, pModule );
NE_CallDllEntryPoint( pModule, DLL_PROCESS_ATTACH );
}
/***********************************************************************
* NE_CreateInstance
*
* If lib_only is TRUE, handle the module like a library even if it is a .EXE
*/
HINSTANCE16 NE_CreateInstance( NE_MODULE *pModule, HINSTANCE16 *prev,
BOOL32 lib_only )
{
SEGTABLEENTRY *pSegment;
int minsize;
HINSTANCE16 hNewInstance;
if (pModule->dgroup == 0)
{
if (prev) *prev = pModule->self;
return pModule->self;
}
pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
if (prev) *prev = pSegment->selector;
/* if it's a library, create a new instance only the first time */
if (pSegment->selector)
{
if (pModule->flags & NE_FFLAGS_LIBMODULE) return pSegment->selector;
if (lib_only) return pSegment->selector;
}
minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
if (pModule->ss == pModule->dgroup) minsize += pModule->stack_size;
minsize += pModule->heap_size;
hNewInstance = GLOBAL_Alloc( GMEM_ZEROINIT | GMEM_FIXED, minsize,
pModule->self, FALSE, FALSE, FALSE );
if (!hNewInstance) return 0;
pSegment->selector = hNewInstance;
return hNewInstance;
}
/***********************************************************************
* PatchCodeHandle
*
* Needed for self-loading modules.
*/
/* It does nothing */
void WINAPI PatchCodeHandle(HANDLE16 hSel)
{
FIXME(module,"(%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( NE_MODULE *pModule )
{
SEGTABLEENTRY *pSegment;
int i, minsize;
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 NE_CreateInstance */
if (i == pModule->dgroup) continue;
pSegment->selector = GLOBAL_Alloc( NE_Ne2MemFlags(pSegment->flags),
minsize, pModule->self,
!(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;
}
/**********************************************************************
* IsSharedSelector (KERNEL.345)
*/
BOOL16 WINAPI IsSharedSelector( HANDLE16 selector )
{
/* Check whether the selector belongs to a DLL */
NE_MODULE *pModule = NE_GetPtr( selector );
if (!pModule) return FALSE;
return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;
}