4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "wine/port.h"
28 #include <sys/types.h>
36 #include "wine/winbase16.h"
40 #include "wine/library.h"
41 #include "kernel_private.h"
42 #include "kernel16_private.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(fixup);
47 WINE_DECLARE_DEBUG_CHANNEL(dll);
48 WINE_DECLARE_DEBUG_CHANNEL(module);
51 * Relocation table entry
53 struct relocation_entry_s
55 BYTE address_type; /* Relocation address type */
56 BYTE relocation_type; /* Relocation type */
57 WORD offset; /* Offset in segment to fixup */
58 WORD target1; /* Target specification */
59 WORD target2; /* Target specification */
63 * Relocation address types
65 #define NE_RADDR_LOWBYTE 0
66 #define NE_RADDR_SELECTOR 2
67 #define NE_RADDR_POINTER32 3
68 #define NE_RADDR_OFFSET16 5
69 #define NE_RADDR_POINTER48 11
70 #define NE_RADDR_OFFSET32 13
75 #define NE_RELTYPE_INTERNAL 0
76 #define NE_RELTYPE_ORDINAL 1
77 #define NE_RELTYPE_NAME 2
78 #define NE_RELTYPE_OSFIXUP 3
79 #define NE_RELFLAG_ADDITIVE 4
81 /* Self-loading modules contain this structure in their first segment */
84 WORD version; /* Must be "A0" (0x3041) */
86 FARPROC16 BootApp; /* startup procedure */
87 FARPROC16 LoadAppSeg; /* procedure to load a segment */
89 FARPROC16 MyAlloc; /* memory allocation procedure,
90 * wine must write this field */
91 FARPROC16 EntryAddrProc;
92 FARPROC16 ExitProc; /* exit procedure */
94 FARPROC16 SetOwner; /* Set Owner procedure, exported by wine */
97 #define SEL(x) ((x)|1)
99 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);
102 /***********************************************************************
103 * NE_GetRelocAddrName
105 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
107 switch(addr_type & 0x7f)
109 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
110 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
111 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
112 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
113 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
114 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
120 /***********************************************************************
123 static HFILE16 NE_OpenFile( NE_MODULE *pModule )
125 char *name = NE_MODULE_NAME( pModule );
126 HANDLE handle = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
127 NULL, OPEN_EXISTING, 0, 0 );
129 if (handle == INVALID_HANDLE_VALUE)
131 ERR( "Can't open file '%s' for module %04x\n", name, pModule->self );
134 return Win32HandleToDosFileHandle( handle );
138 /***********************************************************************
141 * Apply relocations to a segment. Helper for NE_LoadSegment.
143 static inline BOOL apply_relocations( NE_MODULE *pModule, const struct relocation_entry_s *rep,
144 int count, int segnum )
151 FARPROC16 address = 0;
152 HMODULE16 *pModuleTable = (HMODULE16 *)((char *)pModule + pModule->ne_modtab);
153 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
154 SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;
157 * Go through the relocation table one entry at a time.
159 for (i = 0; i < count; i++, rep++)
162 * Get the target address corresponding to this entry.
165 /* If additive, there is no target chain list. Instead, add source
167 int additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
168 switch (rep->relocation_type & 3)
170 case NE_RELTYPE_ORDINAL:
171 module = pModuleTable[rep->target1-1];
172 ordinal = rep->target2;
173 address = NE_GetEntryPoint( module, ordinal );
176 NE_MODULE *pTarget = NE_GetPtr( module );
178 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
179 module, rep->target1,
180 *((BYTE *)pModule + pModule->ne_restab),
181 *((BYTE *)pModule + pModule->ne_restab),
182 (char *)pModule + pModule->ne_restab + 1 );
185 ERR("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
186 *((BYTE *)pTarget + pTarget->ne_restab),
187 (char *)pTarget + pTarget->ne_restab + 1,
189 address = (FARPROC16)0xdeadbeef;
194 NE_MODULE *pTarget = NE_GetPtr( module );
195 TRACE("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
196 *((BYTE *)pTarget + pTarget->ne_restab),
197 (char *)pTarget + pTarget->ne_restab + 1,
198 ordinal, HIWORD(address), LOWORD(address),
199 NE_GetRelocAddrName( rep->address_type, additive ) );
203 case NE_RELTYPE_NAME:
204 module = pModuleTable[rep->target1-1];
205 func_name = (char *)pModule + pModule->ne_imptab + rep->target2;
206 memcpy( buffer, func_name+1, *func_name );
207 buffer[*func_name] = '\0';
209 ordinal = NE_GetOrdinal( module, func_name );
210 address = NE_GetEntryPoint( module, ordinal );
212 if (ERR_ON(fixup) && !address)
214 NE_MODULE *pTarget = NE_GetPtr( module );
215 ERR("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
216 *((BYTE *)pTarget + pTarget->ne_restab),
217 (char *)pTarget + pTarget->ne_restab + 1, func_name );
219 if (!address) address = (FARPROC16) 0xdeadbeef;
222 NE_MODULE *pTarget = NE_GetPtr( module );
223 TRACE("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
224 *((BYTE *)pTarget + pTarget->ne_restab),
225 (char *)pTarget + pTarget->ne_restab + 1,
226 func_name, HIWORD(address), LOWORD(address),
227 NE_GetRelocAddrName( rep->address_type, additive ) );
231 case NE_RELTYPE_INTERNAL:
232 if ((rep->target1 & 0xff) == 0xff)
234 address = NE_GetEntryPoint( pModule->self, rep->target2 );
238 address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
241 TRACE("%d: %04x:%04x %s\n",
242 i + 1, HIWORD(address), LOWORD(address),
243 NE_GetRelocAddrName( rep->address_type, additive ) );
246 case NE_RELTYPE_OSFIXUP:
247 /* Relocation type 7:
249 * These appear to be used as fixups for the Windows
250 * floating point emulator. Let's just ignore them and
251 * try to use the hardware floating point. Linux should
252 * successfully emulate the coprocessor if it doesn't
255 TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
256 i + 1, rep->relocation_type, rep->offset,
257 rep->target1, rep->target2,
258 NE_GetRelocAddrName( rep->address_type, additive ) );
262 offset = rep->offset;
264 /* Apparently, high bit of address_type is sometimes set; */
265 /* we ignore it for now */
266 if (rep->address_type > NE_RADDR_OFFSET32)
269 GetModuleName16( pModule->self, module, sizeof(module) );
270 ERR("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
271 module, rep->address_type );
276 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
277 TRACE(" %04x:%04x\n", offset, *sp );
278 switch (rep->address_type & 0x7f)
280 case NE_RADDR_LOWBYTE:
281 *(BYTE *)sp += LOBYTE((int)address);
283 case NE_RADDR_OFFSET16:
284 *sp += LOWORD(address);
286 case NE_RADDR_POINTER32:
287 *sp += LOWORD(address);
288 *(sp+1) = HIWORD(address);
290 case NE_RADDR_SELECTOR:
291 /* Borland creates additive records with offset zero. Strange, but OK */
293 ERR("Additive selector to %04x.Please report\n",*sp);
295 *sp = HIWORD(address);
301 else /* non-additive fixup */
307 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
309 TRACE(" %04x:%04x\n", offset, *sp );
310 switch (rep->address_type & 0x7f)
312 case NE_RADDR_LOWBYTE:
313 *(BYTE *)sp = LOBYTE((int)address);
315 case NE_RADDR_OFFSET16:
316 *sp = LOWORD(address);
318 case NE_RADDR_POINTER32:
319 *(FARPROC16 *)sp = address;
321 case NE_RADDR_SELECTOR:
322 *sp = SELECTOROF(address);
327 if (next_offset == offset) break; /* avoid infinite loop */
328 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
329 offset = next_offset;
330 } while (offset != 0xffff);
336 WARN("WARNING: %d: unknown ADDR TYPE %d, "
337 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
338 i + 1, rep->address_type, rep->relocation_type,
339 rep->offset, rep->target1, rep->target2);
344 /***********************************************************************
347 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
351 const struct relocation_entry_s *rep;
353 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
354 SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;
356 if (pSeg->flags & NE_SEGFLAGS_LOADED)
358 /* self-loader ? -> already loaded it */
359 if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
362 /* leave, except for DGROUP, as this may be the second instance */
363 if (segnum != pModule->ne_autodata)
367 if (!pSeg->filepos) return TRUE; /* No file image, just return */
369 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
370 segnum, pSeg->hSeg, pSeg->flags );
371 pos = pSeg->filepos << pModule->ne_align;
372 if (pSeg->size) size = pSeg->size;
373 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
375 if (pModule->ne_flags & NE_FFLAGS_SELFLOAD && segnum > 1)
377 /* Implement self-loading segments */
378 SELFLOADHEADER *selfloadheader;
384 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
385 oldstack = NtCurrentTeb()->WOW32Reserved;
386 NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
387 0xff00 - sizeof(STACK16FRAME));
389 hFile16 = NE_OpenFile( pModule );
390 TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=%x,segnum=%d\n",
391 pModule->self,hFile16,segnum );
392 args[2] = pModule->self;
395 WOWCallback16Ex( (DWORD)selfloadheader->LoadAppSeg, WCB16_PASCAL, sizeof(args), args, &ret );
396 pSeg->hSeg = LOWORD(ret);
397 TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
398 _lclose16( hFile16 );
399 NtCurrentTeb()->WOW32Reserved = oldstack;
401 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
403 void *mem = GlobalLock16(pSeg->hSeg);
404 if (!NE_READ_DATA( pModule, mem, pos, size ))
411 The following bit of code for "iterated segments" was written without
412 any documentation on the format of these segments. It seems to work,
413 but may be missing something.
415 const char *buff = NE_GET_DATA( pModule, pos, size );
416 const char* curr = buff;
417 char *mem = GlobalLock16(pSeg->hSeg);
420 if (buff == NULL) return FALSE;
422 while(curr < buff + size) {
423 unsigned int rept = ((short*)curr)[0];
424 unsigned int len = ((short*)curr)[1];
426 curr += 2*sizeof(short);
429 memcpy( mem, curr, len );
436 pSeg->flags |= NE_SEGFLAGS_LOADED;
438 /* Perform exported function prolog fixups */
439 NE_FixupSegmentPrologs( pModule, segnum );
441 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
442 return TRUE; /* No relocation data, we are done */
444 if (!NE_READ_DATA( pModule, &count, pos, sizeof(count) ) || !count) return TRUE;
445 pos += sizeof(count);
447 TRACE("Fixups for %.*s, segment %d, hSeg %04x\n",
448 *((BYTE *)pModule + pModule->ne_restab),
449 (char *)pModule + pModule->ne_restab + 1,
450 segnum, pSeg->hSeg );
452 if (!(rep = NE_GET_DATA( pModule, pos, count * sizeof(struct relocation_entry_s) )))
455 return apply_relocations( pModule, rep, count, segnum );
459 /***********************************************************************
462 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
465 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
467 if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
471 /* Handle self-loading modules */
472 SELFLOADHEADER *selfloadheader;
473 HMODULE16 mod = GetModuleHandle16("KERNEL");
477 TRACE_(module)("%.*s is a self-loading module!\n",
478 *((BYTE*)pModule + pModule->ne_restab),
479 (char *)pModule + pModule->ne_restab + 1);
480 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
481 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) );
482 selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc");
483 selfloadheader->MyAlloc = GetProcAddress16(mod,"MyAlloc");
484 selfloadheader->SetOwner = GetProcAddress16(mod,"FarSetOwner");
485 sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 );
486 pModule->self_loading_sel = SEL(sel);
487 FarSetOwner16( sel, pModule->self );
488 oldstack = NtCurrentTeb()->WOW32Reserved;
489 NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
490 0xff00 - sizeof(STACK16FRAME) );
492 hFile16 = NE_OpenFile(pModule);
493 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
494 pModule->self,hFile16);
495 args[1] = pModule->self;
497 WOWCallback16Ex( (DWORD)selfloadheader->BootApp, WCB16_PASCAL, sizeof(args), args, NULL );
498 TRACE_(dll)("Return from CallBootAppProc\n");
500 NtCurrentTeb()->WOW32Reserved = oldstack;
502 for (i = 2; i <= pModule->ne_cseg; i++)
503 if (!NE_LoadSegment( pModule, i )) return FALSE;
507 for (i = 1; i <= pModule->ne_cseg; i++)
508 if (!NE_LoadSegment( pModule, i )) return FALSE;
514 /***********************************************************************
515 * NE_FixupSegmentPrologs
517 * Fixup exported functions prologs of one segment
519 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
521 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
524 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
527 TRACE("(%d);\n", segnum);
529 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
531 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
535 if (!pModule->ne_autodata) return;
537 if (!(dgroup = SEL(pSegTable[pModule->ne_autodata-1].hSeg))) return;
539 pSeg = MapSL( MAKESEGPTR(sel, 0) );
541 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->ne_enttab);
544 TRACE("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
545 if (!(num_entries = bundle->last - bundle->first))
547 entry = (ET_ENTRY *)((BYTE *)bundle+6);
548 while (num_entries--)
550 /*TRACE("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
551 if (entry->segnum == segnum)
553 pFunc = ((BYTE *)pSeg+entry->offs);
554 TRACE("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
555 if (*(pFunc+2) == 0x90)
557 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
559 TRACE("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
560 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
563 if (*(WORD *)pFunc == 0xd88c)
565 if ((entry->flags & 2)) /* public data ? */
567 TRACE("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
568 *pFunc = 0xb8; /* mov ax, */
569 *(WORD *)(pFunc+1) = dgroup;
572 if ((pModule->ne_flags & NE_FFLAGS_MULTIPLEDATA)
573 && (entry->flags & 1)) /* exported ? */
575 TRACE("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
576 *(WORD *)pFunc = 0x9090; /* nop, nop */
583 } while ( (bundle->next)
584 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
588 /***********************************************************************
589 * PatchCodeHandle (KERNEL.110)
591 * Needed for self-loading modules.
593 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
596 WORD sel = SEL(hSeg);
597 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
598 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
600 TRACE_(module)("(%04x);\n", hSeg);
602 /* find the segment number of the module that belongs to hSeg */
603 for (segnum = 1; segnum <= pModule->ne_cseg; segnum++)
605 if (SEL(pSegTable[segnum-1].hSeg) == sel)
607 NE_FixupSegmentPrologs(pModule, segnum);
612 return MAKELONG(hSeg, sel);
616 /***********************************************************************
617 * NE_GetDLLInitParams
619 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
620 WORD *hInst, WORD *ds, WORD *heap )
622 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
624 if (!(pModule->ne_flags & NE_FFLAGS_SINGLEDATA))
626 if (pModule->ne_flags & NE_FFLAGS_MULTIPLEDATA || pModule->ne_autodata)
629 ERR_(dll)("Library is not marked SINGLEDATA\n");
632 else /* DATA NONE DLL */
638 else /* DATA SINGLE DLL */
640 if (pModule->ne_autodata) {
641 *ds = SEL(pSegTable[pModule->ne_autodata-1].hSeg);
642 *heap = pModule->ne_heap;
644 else /* hmm, DLL has no dgroup,
645 but why has it NE_FFLAGS_SINGLEDATA set ?
646 Buggy DLL compiler ? */
653 *hInst = *ds ? GlobalHandle16(*ds) : pModule->self;
657 /***********************************************************************
660 * Call the DLL initialization code
662 static BOOL NE_InitDLL( NE_MODULE *pModule )
664 SEGTABLEENTRY *pSegTable;
665 WORD hInst, ds, heap;
668 pSegTable = NE_SEG_TABLE( pModule );
670 if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE) ||
671 (pModule->ne_flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
673 /* Call USER signal handler for Win3.1 compatibility. */
674 NE_CallUserSignalProc( pModule->self, USIG16_DLL_LOAD );
676 if (!SELECTOROF(pModule->ne_csip)) return TRUE; /* no initialization code */
679 /* Registers at initialization must be:
681 * di library instance
682 * ds data segment if any
683 * es:si command line (always 0)
686 memset( &context, 0, sizeof(context) );
688 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
693 context.SegEs = ds; /* who knows ... */
694 context.SegFs = wine_get_fs();
695 context.SegGs = wine_get_gs();
696 context.SegCs = SEL(pSegTable[SELECTOROF(pModule->ne_csip)-1].hSeg);
697 context.Eip = OFFSETOF(pModule->ne_csip);
698 context.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + (WORD)&((STACK16FRAME*)0)->bp;
700 pModule->ne_csip = 0; /* Don't initialize it twice */
701 TRACE_(dll)("Calling LibMain for %.*s, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
702 *((BYTE*)pModule + pModule->ne_restab),
703 (char *)pModule + pModule->ne_restab + 1,
704 context.SegCs, context.Eip, context.SegDs,
705 LOWORD(context.Edi), LOWORD(context.Ecx) );
706 WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)&context );
710 /***********************************************************************
713 * Recursively initialize all DLLs (according to the order in which
714 * they where loaded).
716 void NE_InitializeDLLs( HMODULE16 hModule )
721 if (!(pModule = NE_GetPtr( hModule ))) return;
722 assert( !(pModule->ne_flags & NE_FFLAGS_WIN32) );
724 if (pModule->dlls_to_init)
726 HGLOBAL16 to_init = pModule->dlls_to_init;
727 pModule->dlls_to_init = 0;
728 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
730 NE_InitializeDLLs( *pDLL );
732 GlobalFree16( to_init );
734 NE_InitDLL( pModule );
738 /**********************************************************************
739 * NE_CallUserSignalProc
741 * According to "Undocumented Windows", the task signal proc is
742 * bypassed for module load/unload notifications, and the USER signal
743 * proc is called directly instead. This is what this function does.
745 typedef DWORD (WINAPI *pSignalProc)( HANDLE16 module, UINT16 code, UINT16 exit,
746 HINSTANCE16 inst, HQUEUE16 queue );
748 void NE_CallUserSignalProc( HMODULE16 hModule, UINT16 code )
751 HMODULE16 user = GetModuleHandle16("user.exe");
754 if ((proc = GetProcAddress16( user, "SignalProc" )))
756 /* USER is always a builtin dll */
757 pSignalProc sigproc = (pSignalProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)proc ))->target;
758 sigproc( hModule, code, 0, 0, 0 );
763 /***********************************************************************
764 * NE_CallDllEntryPoint
766 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
768 typedef DWORD (WINAPI *WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
770 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
772 WORD hInst, ds, heap;
773 FARPROC16 entryPoint;
775 if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE)) return;
776 if (!(pModule->ne_flags & NE_FFLAGS_BUILTIN) && pModule->ne_expver < 0x0400) return;
777 if (!(entryPoint = GetProcAddress16( pModule->self, "DllEntryPoint" ))) return;
779 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
781 TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
782 NE_MODULE_NAME( pModule ),
783 SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
785 if ( pModule->ne_flags & NE_FFLAGS_BUILTIN )
787 WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target;
789 entryProc( dwReason, hInst, ds, heap, 0, 0 );
796 memset( &context, 0, sizeof(context) );
798 context.SegEs = ds; /* who knows ... */
799 context.SegFs = wine_get_fs();
800 context.SegGs = wine_get_gs();
801 context.SegCs = HIWORD(entryPoint);
802 context.Eip = LOWORD(entryPoint);
803 context.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + (WORD)&((STACK16FRAME*)0)->bp;
805 args[7] = HIWORD(dwReason);
806 args[6] = LOWORD(dwReason);
810 args[2] = 0; /* HIWORD(dwReserved1) */
811 args[1] = 0; /* LOWORD(dwReserved1) */
812 args[0] = 0; /* wReserved2 */
813 WOWCallback16Ex( 0, WCB16_REGS, sizeof(args), args, (DWORD *)&context );
817 /***********************************************************************
818 * NE_DllProcessAttach
820 * Call the DllEntryPoint of all modules this one (recursively)
821 * depends on, according to the order in which they were loaded.
823 * Note that --as opposed to the PE module case-- there is no notion
824 * of 'module loaded into a process' for NE modules, and hence we
825 * have no place to store the fact that the DllEntryPoint of a
826 * given module was already called on behalf of this process (e.g.
827 * due to some earlier LoadLibrary16 call).
829 * Thus, we just call the DllEntryPoint twice in that case. Win9x
830 * appears to behave this way as well ...
832 * This routine must only be called with the Win16Lock held.
834 * FIXME: We should actually abort loading in case the DllEntryPoint
846 static void add_to_init_list( struct ne_init_list *list, NE_MODULE *hModule )
848 NE_MODULE **newModule = NULL;
849 if ( list->count == list->size )
851 int newSize = list->size + 128;
854 newModule = HeapReAlloc( GetProcessHeap(), 0,
855 list->module, newSize*sizeof(NE_MODULE *) );
857 newModule = HeapAlloc( GetProcessHeap(), 0,
858 newSize*sizeof(NE_MODULE *) );
861 FIXME_(dll)("Out of memory!\n");
865 list->module = newModule;
866 list->size = newSize;
869 list->module[list->count++] = hModule;
872 static void free_init_list( struct ne_init_list *list )
876 HeapFree( GetProcessHeap(), 0, list->module );
877 memset( list, 0, sizeof(*list) );
881 static void fill_init_list( struct ne_init_list *list, HMODULE16 hModule )
887 if (!(pModule = NE_GetPtr( hModule ))) return;
888 assert( !(pModule->ne_flags & NE_FFLAGS_WIN32) );
890 /* Never add a module twice */
891 for ( i = 0; i < list->count; i++ )
892 if ( list->module[i] == pModule )
895 /* Check for recursive call */
896 if ( pModule->ne_flagsothers & 0x80 ) return;
898 TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
900 /* Tag current module to prevent recursive loop */
901 pModule->ne_flagsothers |= 0x80;
903 /* Recursively attach all DLLs this one depends on */
904 pModRef = (HMODULE16 *)((char *)pModule + pModule->ne_modtab);
905 for ( i = 0; i < pModule->ne_cmod; i++ )
906 if ( pModRef[i] ) fill_init_list( list, pModRef[i] );
908 /* Add current module */
909 add_to_init_list( list, pModule );
911 /* Remove recursion flag */
912 pModule->ne_flagsothers &= ~0x80;
914 TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
917 static void call_init_list( struct ne_init_list *list )
920 for ( i = 0; i < list->count; i++ )
921 NE_CallDllEntryPoint( list->module[i], DLL_PROCESS_ATTACH );
924 void NE_DllProcessAttach( HMODULE16 hModule )
926 struct ne_init_list list;
927 memset( &list, 0, sizeof(list) );
929 fill_init_list( &list, hModule );
930 call_init_list( &list );
931 free_init_list( &list );
935 /***********************************************************************
938 * This function translates NE segment flags to GlobalAlloc flags
940 static WORD NE_Ne2MemFlags(WORD flags)
944 if (flags & NE_SEGFLAGS_DISCARDABLE)
945 memflags |= GMEM_DISCARDABLE;
946 if (flags & NE_SEGFLAGS_MOVEABLE ||
947 ( ! (flags & NE_SEGFLAGS_DATA) &&
948 ! (flags & NE_SEGFLAGS_LOADED) &&
949 ! (flags & NE_SEGFLAGS_ALLOCATED)
952 memflags |= GMEM_MOVEABLE;
953 memflags |= GMEM_ZEROINIT;
955 memflags = GMEM_ZEROINIT | GMEM_FIXED;
960 /***********************************************************************
961 * MyAlloc (KERNEL.668) Wine-specific export
963 * MyAlloc() function for self-loading apps.
965 DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
967 WORD size = wSize << wElem;
970 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
971 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
973 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
974 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
976 WORD hSel = SEL(hMem);
977 WORD access = SelectorAccessRights16(hSel,0,0);
979 access |= 2<<2; /* SEGMENT_CODE */
980 SelectorAccessRights16(hSel,1,access);
983 return MAKELONG( hMem, SEL(hMem) );
985 return MAKELONG( 0, hMem );
988 /***********************************************************************
991 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
993 if ( !pModule->ne_autodata )
994 return pModule->self;
998 pSeg = NE_SEG_TABLE( pModule ) + pModule->ne_autodata - 1;
1003 /***********************************************************************
1006 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
1008 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
1010 unsigned char selflags;
1012 assert( !(pModule->ne_flags & NE_FFLAGS_WIN32) );
1014 if ( segnum < 1 || segnum > pModule->ne_cseg )
1017 if ( (pModule->ne_flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
1018 return TRUE; /* selfloader allocates segment itself */
1020 if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->ne_autodata )
1021 return TRUE; /* all but DGROUP only allocated once */
1023 minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
1024 if ( segnum == SELECTOROF(pModule->ne_sssp) ) minsize += pModule->ne_stack;
1025 if ( segnum == pModule->ne_autodata ) minsize += pModule->ne_heap;
1027 selflags = (pSeg->flags & NE_SEGFLAGS_DATA) ? WINE_LDT_FLAGS_DATA : WINE_LDT_FLAGS_CODE;
1028 if (pSeg->flags & NE_SEGFLAGS_32BIT) selflags |= WINE_LDT_FLAGS_32BIT;
1029 pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags), minsize, pModule->self, selflags );
1030 if (!pSeg->hSeg) return FALSE;
1032 pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
1036 /***********************************************************************
1037 * NE_CreateAllSegments
1039 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
1042 for ( i = 1; i <= pModule->ne_cseg; i++ )
1043 if ( !NE_CreateSegment( pModule, i ) )
1046 pModule->dgroup_entry = pModule->ne_autodata ? pModule->ne_segtab +
1047 (pModule->ne_autodata - 1) * sizeof(SEGTABLEENTRY) : 0;
1052 /**********************************************************************
1053 * IsSharedSelector (KERNEL.345)
1055 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
1057 /* Check whether the selector belongs to a DLL */
1058 NE_MODULE *pModule = NE_GetPtr( selector );
1059 if (!pModule) return FALSE;
1060 return (pModule->ne_flags & NE_FFLAGS_LIBMODULE) != 0;