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"
39 #include "wine/library.h"
40 #include "kernel_private.h"
41 #include "kernel16_private.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(fixup);
46 WINE_DECLARE_DEBUG_CHANNEL(dll);
47 WINE_DECLARE_DEBUG_CHANNEL(module);
50 * Relocation table entry
52 struct relocation_entry_s
54 BYTE address_type; /* Relocation address type */
55 BYTE relocation_type; /* Relocation type */
56 WORD offset; /* Offset in segment to fixup */
57 WORD target1; /* Target specification */
58 WORD target2; /* Target specification */
62 * Relocation address types
64 #define NE_RADDR_LOWBYTE 0
65 #define NE_RADDR_SELECTOR 2
66 #define NE_RADDR_POINTER32 3
67 #define NE_RADDR_OFFSET16 5
68 #define NE_RADDR_POINTER48 11
69 #define NE_RADDR_OFFSET32 13
74 #define NE_RELTYPE_INTERNAL 0
75 #define NE_RELTYPE_ORDINAL 1
76 #define NE_RELTYPE_NAME 2
77 #define NE_RELTYPE_OSFIXUP 3
78 #define NE_RELFLAG_ADDITIVE 4
80 /* Self-loading modules contain this structure in their first segment */
83 WORD version; /* Must be "A0" (0x3041) */
85 FARPROC16 BootApp; /* startup procedure */
86 FARPROC16 LoadAppSeg; /* procedure to load a segment */
88 FARPROC16 MyAlloc; /* memory allocation procedure,
89 * wine must write this field */
90 FARPROC16 EntryAddrProc;
91 FARPROC16 ExitProc; /* exit procedure */
93 FARPROC16 SetOwner; /* Set Owner procedure, exported by wine */
96 #define SEL(x) ((x)|1)
98 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);
101 /***********************************************************************
102 * NE_GetRelocAddrName
104 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
106 switch(addr_type & 0x7f)
108 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
109 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
110 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
111 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
112 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
113 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
119 /***********************************************************************
122 static HFILE16 NE_OpenFile( NE_MODULE *pModule )
124 char *name = NE_MODULE_NAME( pModule );
125 HANDLE handle = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
126 NULL, OPEN_EXISTING, 0, 0 );
128 if (handle == INVALID_HANDLE_VALUE)
130 ERR( "Can't open file '%s' for module %04x\n", name, pModule->self );
133 return Win32HandleToDosFileHandle( handle );
137 /***********************************************************************
140 * Apply relocations to a segment. Helper for NE_LoadSegment.
142 static inline BOOL apply_relocations( NE_MODULE *pModule, const struct relocation_entry_s *rep,
143 int count, int segnum )
150 FARPROC16 address = 0;
151 HMODULE16 *pModuleTable = (HMODULE16 *)((char *)pModule + pModule->ne_modtab);
152 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
153 SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;
156 * Go through the relocation table one entry at a time.
158 for (i = 0; i < count; i++, rep++)
161 * Get the target address corresponding to this entry.
164 /* If additive, there is no target chain list. Instead, add source
166 int additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
167 switch (rep->relocation_type & 3)
169 case NE_RELTYPE_ORDINAL:
170 module = pModuleTable[rep->target1-1];
171 ordinal = rep->target2;
172 address = NE_GetEntryPoint( module, ordinal );
175 NE_MODULE *pTarget = NE_GetPtr( module );
177 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
178 module, rep->target1,
179 *((BYTE *)pModule + pModule->ne_restab),
180 *((BYTE *)pModule + pModule->ne_restab),
181 (char *)pModule + pModule->ne_restab + 1 );
184 ERR("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
185 *((BYTE *)pTarget + pTarget->ne_restab),
186 (char *)pTarget + pTarget->ne_restab + 1,
188 address = (FARPROC16)0xdeadbeef;
193 NE_MODULE *pTarget = NE_GetPtr( module );
194 TRACE("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
195 *((BYTE *)pTarget + pTarget->ne_restab),
196 (char *)pTarget + pTarget->ne_restab + 1,
197 ordinal, HIWORD(address), LOWORD(address),
198 NE_GetRelocAddrName( rep->address_type, additive ) );
202 case NE_RELTYPE_NAME:
203 module = pModuleTable[rep->target1-1];
204 func_name = (char *)pModule + pModule->ne_imptab + rep->target2;
205 memcpy( buffer, func_name+1, *func_name );
206 buffer[*func_name] = '\0';
208 ordinal = NE_GetOrdinal( module, func_name );
209 address = NE_GetEntryPoint( module, ordinal );
211 if (ERR_ON(fixup) && !address)
213 NE_MODULE *pTarget = NE_GetPtr( module );
214 ERR("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
215 *((BYTE *)pTarget + pTarget->ne_restab),
216 (char *)pTarget + pTarget->ne_restab + 1, func_name );
218 if (!address) address = (FARPROC16) 0xdeadbeef;
221 NE_MODULE *pTarget = NE_GetPtr( module );
222 TRACE("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
223 *((BYTE *)pTarget + pTarget->ne_restab),
224 (char *)pTarget + pTarget->ne_restab + 1,
225 func_name, HIWORD(address), LOWORD(address),
226 NE_GetRelocAddrName( rep->address_type, additive ) );
230 case NE_RELTYPE_INTERNAL:
231 if ((rep->target1 & 0xff) == 0xff)
233 address = NE_GetEntryPoint( pModule->self, rep->target2 );
237 address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
240 TRACE("%d: %04x:%04x %s\n",
241 i + 1, HIWORD(address), LOWORD(address),
242 NE_GetRelocAddrName( rep->address_type, additive ) );
245 case NE_RELTYPE_OSFIXUP:
246 /* Relocation type 7:
248 * These appear to be used as fixups for the Windows
249 * floating point emulator. Let's just ignore them and
250 * try to use the hardware floating point. Linux should
251 * successfully emulate the coprocessor if it doesn't
254 TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
255 i + 1, rep->relocation_type, rep->offset,
256 rep->target1, rep->target2,
257 NE_GetRelocAddrName( rep->address_type, additive ) );
261 offset = rep->offset;
263 /* Apparently, high bit of address_type is sometimes set; */
264 /* we ignore it for now */
265 if (rep->address_type > NE_RADDR_OFFSET32)
268 GetModuleName16( pModule->self, module, sizeof(module) );
269 ERR("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
270 module, rep->address_type );
275 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
276 TRACE(" %04x:%04x\n", offset, *sp );
277 switch (rep->address_type & 0x7f)
279 case NE_RADDR_LOWBYTE:
280 *(BYTE *)sp += LOBYTE((int)address);
282 case NE_RADDR_OFFSET16:
283 *sp += LOWORD(address);
285 case NE_RADDR_POINTER32:
286 *sp += LOWORD(address);
287 *(sp+1) = HIWORD(address);
289 case NE_RADDR_SELECTOR:
290 /* Borland creates additive records with offset zero. Strange, but OK */
292 ERR("Additive selector to %04x.Please report\n",*sp);
294 *sp = HIWORD(address);
300 else /* non-additive fixup */
306 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
308 TRACE(" %04x:%04x\n", offset, *sp );
309 switch (rep->address_type & 0x7f)
311 case NE_RADDR_LOWBYTE:
312 *(BYTE *)sp = LOBYTE((int)address);
314 case NE_RADDR_OFFSET16:
315 *sp = LOWORD(address);
317 case NE_RADDR_POINTER32:
318 *(FARPROC16 *)sp = address;
320 case NE_RADDR_SELECTOR:
321 *sp = SELECTOROF(address);
326 if (next_offset == offset) break; /* avoid infinite loop */
327 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
328 offset = next_offset;
329 } while (offset != 0xffff);
335 WARN("WARNING: %d: unknown ADDR TYPE %d, "
336 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
337 i + 1, rep->address_type, rep->relocation_type,
338 rep->offset, rep->target1, rep->target2);
343 /***********************************************************************
346 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
350 const struct relocation_entry_s *rep;
352 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
353 SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;
355 if (pSeg->flags & NE_SEGFLAGS_LOADED)
357 /* self-loader ? -> already loaded it */
358 if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
361 /* leave, except for DGROUP, as this may be the second instance */
362 if (segnum != pModule->ne_autodata)
366 if (!pSeg->filepos) return TRUE; /* No file image, just return */
368 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
369 segnum, pSeg->hSeg, pSeg->flags );
370 pos = pSeg->filepos << pModule->ne_align;
371 if (pSeg->size) size = pSeg->size;
372 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
374 if (pModule->ne_flags & NE_FFLAGS_SELFLOAD && segnum > 1)
376 /* Implement self-loading segments */
377 SELFLOADHEADER *selfloadheader;
383 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
384 oldstack = NtCurrentTeb()->WOW32Reserved;
385 NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
386 0xff00 - sizeof(STACK16FRAME));
388 hFile16 = NE_OpenFile( pModule );
389 TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=%x,segnum=%d\n",
390 pModule->self,hFile16,segnum );
391 args[2] = pModule->self;
394 WOWCallback16Ex( (DWORD)selfloadheader->LoadAppSeg, WCB16_PASCAL, sizeof(args), args, &ret );
395 pSeg->hSeg = LOWORD(ret);
396 TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
397 _lclose16( hFile16 );
398 NtCurrentTeb()->WOW32Reserved = oldstack;
400 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
402 void *mem = GlobalLock16(pSeg->hSeg);
403 if (!NE_READ_DATA( pModule, mem, pos, size ))
410 The following bit of code for "iterated segments" was written without
411 any documentation on the format of these segments. It seems to work,
412 but may be missing something.
414 const char *buff = NE_GET_DATA( pModule, pos, size );
415 const char* curr = buff;
416 char *mem = GlobalLock16(pSeg->hSeg);
419 if (buff == NULL) return FALSE;
421 while(curr < buff + size) {
422 unsigned int rept = ((short*)curr)[0];
423 unsigned int len = ((short*)curr)[1];
425 curr += 2*sizeof(short);
428 memcpy( mem, curr, len );
435 pSeg->flags |= NE_SEGFLAGS_LOADED;
437 /* Perform exported function prolog fixups */
438 NE_FixupSegmentPrologs( pModule, segnum );
440 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
441 return TRUE; /* No relocation data, we are done */
443 if (!NE_READ_DATA( pModule, &count, pos, sizeof(count) ) || !count) return TRUE;
444 pos += sizeof(count);
446 TRACE("Fixups for %.*s, segment %d, hSeg %04x\n",
447 *((BYTE *)pModule + pModule->ne_restab),
448 (char *)pModule + pModule->ne_restab + 1,
449 segnum, pSeg->hSeg );
451 if (!(rep = NE_GET_DATA( pModule, pos, count * sizeof(struct relocation_entry_s) )))
454 return apply_relocations( pModule, rep, count, segnum );
458 /***********************************************************************
461 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
464 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
466 if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
470 /* Handle self-loading modules */
471 SELFLOADHEADER *selfloadheader;
472 HMODULE16 mod = GetModuleHandle16("KERNEL");
476 TRACE_(module)("%.*s is a self-loading module!\n",
477 *((BYTE*)pModule + pModule->ne_restab),
478 (char *)pModule + pModule->ne_restab + 1);
479 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
480 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) );
481 selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc");
482 selfloadheader->MyAlloc = GetProcAddress16(mod,"MyAlloc");
483 selfloadheader->SetOwner = GetProcAddress16(mod,"FarSetOwner");
484 sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 );
485 pModule->self_loading_sel = SEL(sel);
486 FarSetOwner16( sel, pModule->self );
487 oldstack = NtCurrentTeb()->WOW32Reserved;
488 NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
489 0xff00 - sizeof(STACK16FRAME) );
491 hFile16 = NE_OpenFile(pModule);
492 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
493 pModule->self,hFile16);
494 args[1] = pModule->self;
496 WOWCallback16Ex( (DWORD)selfloadheader->BootApp, WCB16_PASCAL, sizeof(args), args, NULL );
497 TRACE_(dll)("Return from CallBootAppProc\n");
499 NtCurrentTeb()->WOW32Reserved = oldstack;
501 for (i = 2; i <= pModule->ne_cseg; i++)
502 if (!NE_LoadSegment( pModule, i )) return FALSE;
506 for (i = 1; i <= pModule->ne_cseg; i++)
507 if (!NE_LoadSegment( pModule, i )) return FALSE;
513 /***********************************************************************
514 * NE_FixupSegmentPrologs
516 * Fixup exported functions prologs of one segment
518 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
520 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
523 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
526 TRACE("(%d);\n", segnum);
528 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
530 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
534 if (!pModule->ne_autodata) return;
536 if (!(dgroup = SEL(pSegTable[pModule->ne_autodata-1].hSeg))) return;
538 pSeg = MapSL( MAKESEGPTR(sel, 0) );
540 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->ne_enttab);
543 TRACE("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
544 if (!(num_entries = bundle->last - bundle->first))
546 entry = (ET_ENTRY *)((BYTE *)bundle+6);
547 while (num_entries--)
549 /*TRACE("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
550 if (entry->segnum == segnum)
552 pFunc = ((BYTE *)pSeg+entry->offs);
553 TRACE("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
554 if (*(pFunc+2) == 0x90)
556 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
558 TRACE("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
559 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
562 if (*(WORD *)pFunc == 0xd88c)
564 if ((entry->flags & 2)) /* public data ? */
566 TRACE("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
567 *pFunc = 0xb8; /* mov ax, */
568 *(WORD *)(pFunc+1) = dgroup;
571 if ((pModule->ne_flags & NE_FFLAGS_MULTIPLEDATA)
572 && (entry->flags & 1)) /* exported ? */
574 TRACE("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
575 *(WORD *)pFunc = 0x9090; /* nop, nop */
582 } while ( (bundle->next)
583 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
587 /***********************************************************************
588 * PatchCodeHandle (KERNEL.110)
590 * Needed for self-loading modules.
592 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
595 WORD sel = SEL(hSeg);
596 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
597 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
599 TRACE_(module)("(%04x);\n", hSeg);
601 /* find the segment number of the module that belongs to hSeg */
602 for (segnum = 1; segnum <= pModule->ne_cseg; segnum++)
604 if (SEL(pSegTable[segnum-1].hSeg) == sel)
606 NE_FixupSegmentPrologs(pModule, segnum);
611 return MAKELONG(hSeg, sel);
615 /***********************************************************************
616 * NE_GetDLLInitParams
618 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
619 WORD *hInst, WORD *ds, WORD *heap )
621 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
623 if (!(pModule->ne_flags & NE_FFLAGS_SINGLEDATA))
625 if (pModule->ne_flags & NE_FFLAGS_MULTIPLEDATA || pModule->ne_autodata)
628 ERR_(dll)("Library is not marked SINGLEDATA\n");
631 else /* DATA NONE DLL */
637 else /* DATA SINGLE DLL */
639 if (pModule->ne_autodata) {
640 *ds = SEL(pSegTable[pModule->ne_autodata-1].hSeg);
641 *heap = pModule->ne_heap;
643 else /* hmm, DLL has no dgroup,
644 but why has it NE_FFLAGS_SINGLEDATA set ?
645 Buggy DLL compiler ? */
652 *hInst = *ds ? GlobalHandle16(*ds) : pModule->self;
656 /***********************************************************************
659 * Call the DLL initialization code
661 static BOOL NE_InitDLL( NE_MODULE *pModule )
663 SEGTABLEENTRY *pSegTable;
664 WORD hInst, ds, heap;
667 pSegTable = NE_SEG_TABLE( pModule );
669 if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE) ||
670 (pModule->ne_flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
672 /* Call USER signal handler for Win3.1 compatibility. */
673 NE_CallUserSignalProc( pModule->self, USIG16_DLL_LOAD );
675 if (!SELECTOROF(pModule->ne_csip)) return TRUE; /* no initialization code */
678 /* Registers at initialization must be:
680 * di library instance
681 * ds data segment if any
682 * es:si command line (always 0)
685 memset( &context, 0, sizeof(context) );
687 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
692 context.SegEs = ds; /* who knows ... */
693 context.SegFs = wine_get_fs();
694 context.SegGs = wine_get_gs();
695 context.SegCs = SEL(pSegTable[SELECTOROF(pModule->ne_csip)-1].hSeg);
696 context.Eip = OFFSETOF(pModule->ne_csip);
697 context.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + (WORD)&((STACK16FRAME*)0)->bp;
699 pModule->ne_csip = 0; /* Don't initialize it twice */
700 TRACE_(dll)("Calling LibMain for %.*s, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
701 *((BYTE*)pModule + pModule->ne_restab),
702 (char *)pModule + pModule->ne_restab + 1,
703 context.SegCs, context.Eip, context.SegDs,
704 LOWORD(context.Edi), LOWORD(context.Ecx) );
705 WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)&context );
709 /***********************************************************************
712 * Recursively initialize all DLLs (according to the order in which
713 * they where loaded).
715 void NE_InitializeDLLs( HMODULE16 hModule )
720 if (!(pModule = NE_GetPtr( hModule ))) return;
721 assert( !(pModule->ne_flags & NE_FFLAGS_WIN32) );
723 if (pModule->dlls_to_init)
725 HGLOBAL16 to_init = pModule->dlls_to_init;
726 pModule->dlls_to_init = 0;
727 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
729 NE_InitializeDLLs( *pDLL );
731 GlobalFree16( to_init );
733 NE_InitDLL( pModule );
737 /**********************************************************************
738 * NE_CallUserSignalProc
740 * According to "Undocumented Windows", the task signal proc is
741 * bypassed for module load/unload notifications, and the USER signal
742 * proc is called directly instead. This is what this function does.
744 typedef DWORD (WINAPI *pSignalProc)( HANDLE16 module, UINT16 code, UINT16 exit,
745 HINSTANCE16 inst, HQUEUE16 queue );
747 void NE_CallUserSignalProc( HMODULE16 hModule, UINT16 code )
750 HMODULE16 user = GetModuleHandle16("user.exe");
753 if ((proc = GetProcAddress16( user, "SignalProc" )))
755 /* USER is always a builtin dll */
756 pSignalProc sigproc = (pSignalProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)proc ))->target;
757 sigproc( hModule, code, 0, 0, 0 );
762 /***********************************************************************
763 * NE_CallDllEntryPoint
765 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
767 typedef DWORD (WINAPI *WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
769 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
771 WORD hInst, ds, heap;
772 FARPROC16 entryPoint;
774 if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE)) return;
775 if (!(pModule->ne_flags & NE_FFLAGS_BUILTIN) && pModule->ne_expver < 0x0400) return;
776 if (!(entryPoint = GetProcAddress16( pModule->self, "DllEntryPoint" ))) return;
778 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
780 TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
781 NE_MODULE_NAME( pModule ),
782 SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
784 if ( pModule->ne_flags & NE_FFLAGS_BUILTIN )
786 WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target;
788 entryProc( dwReason, hInst, ds, heap, 0, 0 );
795 memset( &context, 0, sizeof(context) );
797 context.SegEs = ds; /* who knows ... */
798 context.SegFs = wine_get_fs();
799 context.SegGs = wine_get_gs();
800 context.SegCs = HIWORD(entryPoint);
801 context.Eip = LOWORD(entryPoint);
802 context.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + (WORD)&((STACK16FRAME*)0)->bp;
804 args[7] = HIWORD(dwReason);
805 args[6] = LOWORD(dwReason);
809 args[2] = 0; /* HIWORD(dwReserved1) */
810 args[1] = 0; /* LOWORD(dwReserved1) */
811 args[0] = 0; /* wReserved2 */
812 WOWCallback16Ex( 0, WCB16_REGS, sizeof(args), args, (DWORD *)&context );
816 /***********************************************************************
817 * NE_DllProcessAttach
819 * Call the DllEntryPoint of all modules this one (recursively)
820 * depends on, according to the order in which they were loaded.
822 * Note that --as opposed to the PE module case-- there is no notion
823 * of 'module loaded into a process' for NE modules, and hence we
824 * have no place to store the fact that the DllEntryPoint of a
825 * given module was already called on behalf of this process (e.g.
826 * due to some earlier LoadLibrary16 call).
828 * Thus, we just call the DllEntryPoint twice in that case. Win9x
829 * appears to behave this way as well ...
831 * This routine must only be called with the Win16Lock held.
833 * FIXME: We should actually abort loading in case the DllEntryPoint
845 static void add_to_init_list( struct ne_init_list *list, NE_MODULE *hModule )
847 NE_MODULE **newModule = NULL;
848 if ( list->count == list->size )
850 int newSize = list->size + 128;
853 newModule = HeapReAlloc( GetProcessHeap(), 0,
854 list->module, newSize*sizeof(NE_MODULE *) );
856 newModule = HeapAlloc( GetProcessHeap(), 0,
857 newSize*sizeof(NE_MODULE *) );
860 FIXME_(dll)("Out of memory!\n");
864 list->module = newModule;
865 list->size = newSize;
868 list->module[list->count++] = hModule;
871 static void free_init_list( struct ne_init_list *list )
875 HeapFree( GetProcessHeap(), 0, list->module );
876 memset( list, 0, sizeof(*list) );
880 static void fill_init_list( struct ne_init_list *list, HMODULE16 hModule )
886 if (!(pModule = NE_GetPtr( hModule ))) return;
887 assert( !(pModule->ne_flags & NE_FFLAGS_WIN32) );
889 /* Never add a module twice */
890 for ( i = 0; i < list->count; i++ )
891 if ( list->module[i] == pModule )
894 /* Check for recursive call */
895 if ( pModule->ne_flagsothers & 0x80 ) return;
897 TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
899 /* Tag current module to prevent recursive loop */
900 pModule->ne_flagsothers |= 0x80;
902 /* Recursively attach all DLLs this one depends on */
903 pModRef = (HMODULE16 *)((char *)pModule + pModule->ne_modtab);
904 for ( i = 0; i < pModule->ne_cmod; i++ )
905 if ( pModRef[i] ) fill_init_list( list, pModRef[i] );
907 /* Add current module */
908 add_to_init_list( list, pModule );
910 /* Remove recursion flag */
911 pModule->ne_flagsothers &= ~0x80;
913 TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
916 static void call_init_list( struct ne_init_list *list )
919 for ( i = 0; i < list->count; i++ )
920 NE_CallDllEntryPoint( list->module[i], DLL_PROCESS_ATTACH );
923 void NE_DllProcessAttach( HMODULE16 hModule )
925 struct ne_init_list list;
926 memset( &list, 0, sizeof(list) );
928 fill_init_list( &list, hModule );
929 call_init_list( &list );
930 free_init_list( &list );
934 /***********************************************************************
937 * This function translates NE segment flags to GlobalAlloc flags
939 static WORD NE_Ne2MemFlags(WORD flags)
943 if (flags & NE_SEGFLAGS_DISCARDABLE)
944 memflags |= GMEM_DISCARDABLE;
945 if (flags & NE_SEGFLAGS_MOVEABLE ||
946 ( ! (flags & NE_SEGFLAGS_DATA) &&
947 ! (flags & NE_SEGFLAGS_LOADED) &&
948 ! (flags & NE_SEGFLAGS_ALLOCATED)
951 memflags |= GMEM_MOVEABLE;
952 memflags |= GMEM_ZEROINIT;
954 memflags = GMEM_ZEROINIT | GMEM_FIXED;
959 /***********************************************************************
960 * MyAlloc (KERNEL.668) Wine-specific export
962 * MyAlloc() function for self-loading apps.
964 DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
966 WORD size = wSize << wElem;
969 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
970 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
972 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
973 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
975 WORD hSel = SEL(hMem);
976 WORD access = SelectorAccessRights16(hSel,0,0);
978 access |= 2<<2; /* SEGMENT_CODE */
979 SelectorAccessRights16(hSel,1,access);
982 return MAKELONG( hMem, SEL(hMem) );
984 return MAKELONG( 0, hMem );
987 /***********************************************************************
990 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
992 if ( !pModule->ne_autodata )
993 return pModule->self;
997 pSeg = NE_SEG_TABLE( pModule ) + pModule->ne_autodata - 1;
1002 /***********************************************************************
1005 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
1007 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
1009 unsigned char selflags;
1011 assert( !(pModule->ne_flags & NE_FFLAGS_WIN32) );
1013 if ( segnum < 1 || segnum > pModule->ne_cseg )
1016 if ( (pModule->ne_flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
1017 return TRUE; /* selfloader allocates segment itself */
1019 if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->ne_autodata )
1020 return TRUE; /* all but DGROUP only allocated once */
1022 minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
1023 if ( segnum == SELECTOROF(pModule->ne_sssp) ) minsize += pModule->ne_stack;
1024 if ( segnum == pModule->ne_autodata ) minsize += pModule->ne_heap;
1026 selflags = (pSeg->flags & NE_SEGFLAGS_DATA) ? WINE_LDT_FLAGS_DATA : WINE_LDT_FLAGS_CODE;
1027 if (pSeg->flags & NE_SEGFLAGS_32BIT) selflags |= WINE_LDT_FLAGS_32BIT;
1028 pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags), minsize, pModule->self, selflags );
1029 if (!pSeg->hSeg) return FALSE;
1031 pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
1035 /***********************************************************************
1036 * NE_CreateAllSegments
1038 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
1041 for ( i = 1; i <= pModule->ne_cseg; i++ )
1042 if ( !NE_CreateSegment( pModule, i ) )
1045 pModule->dgroup_entry = pModule->ne_autodata ? pModule->ne_segtab +
1046 (pModule->ne_autodata - 1) * sizeof(SEGTABLEENTRY) : 0;
1051 /**********************************************************************
1052 * IsSharedSelector (KERNEL.345)
1054 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
1056 /* Check whether the selector belongs to a DLL */
1057 NE_MODULE *pModule = NE_GetPtr( selector );
1058 if (!pModule) return FALSE;
1059 return (pModule->ne_flags & NE_FFLAGS_LIBMODULE) != 0;