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"
37 #include "wine/library.h"
42 #include "stackframe.h"
43 #include "builtin16.h"
44 #include "wine/debug.h"
46 WINE_DECLARE_DEBUG_CHANNEL(dll);
47 WINE_DECLARE_DEBUG_CHANNEL(fixup);
48 WINE_DECLARE_DEBUG_CHANNEL(module);
49 WINE_DECLARE_DEBUG_CHANNEL(segment);
52 * Relocation table entry
54 struct relocation_entry_s
56 BYTE address_type; /* Relocation address type */
57 BYTE relocation_type; /* Relocation type */
58 WORD offset; /* Offset in segment to fixup */
59 WORD target1; /* Target specification */
60 WORD target2; /* Target specification */
64 * Relocation address types
66 #define NE_RADDR_LOWBYTE 0
67 #define NE_RADDR_SELECTOR 2
68 #define NE_RADDR_POINTER32 3
69 #define NE_RADDR_OFFSET16 5
70 #define NE_RADDR_POINTER48 11
71 #define NE_RADDR_OFFSET32 13
76 #define NE_RELTYPE_INTERNAL 0
77 #define NE_RELTYPE_ORDINAL 1
78 #define NE_RELTYPE_NAME 2
79 #define NE_RELTYPE_OSFIXUP 3
80 #define NE_RELFLAG_ADDITIVE 4
82 #define SEL(x) ((x)|1)
84 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);
86 /* ### start build ### */
87 extern WORD CALLBACK NE_CallTo16_word_ww(FARPROC16,WORD,WORD);
88 extern WORD CALLBACK NE_CallTo16_word_www(FARPROC16,WORD,WORD,WORD);
89 /* ### stop build ### */
91 /***********************************************************************
94 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
96 switch(addr_type & 0x7f)
98 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
99 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
100 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
101 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
102 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
103 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
109 /***********************************************************************
112 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
114 SEGTABLEENTRY *pSegTable, *pSeg;
116 WORD count, i, offset, next_offset;
118 FARPROC16 address = 0;
121 struct relocation_entry_s *rep, *reloc_entries;
127 int ordinal, additive;
130 pSegTable = NE_SEG_TABLE( pModule );
131 pSeg = pSegTable + segnum - 1;
133 if (pSeg->flags & NE_SEGFLAGS_LOADED)
135 /* self-loader ? -> already loaded it */
136 if (pModule->flags & NE_FFLAGS_SELFLOAD)
139 /* leave, except for DGROUP, as this may be the second instance */
140 if (segnum != pModule->dgroup)
144 if (!pSeg->filepos) return TRUE; /* No file image, just return */
146 pModuleTable = NE_MODULE_TABLE( pModule );
148 hf = NE_OpenFile( pModule );
149 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
150 segnum, pSeg->hSeg, pSeg->flags );
151 SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
152 if (pSeg->size) size = pSeg->size;
153 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
154 mem = GlobalLock16(pSeg->hSeg);
155 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
157 /* Implement self-loading segments */
158 SELFLOADHEADER *selfloadheader;
163 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
164 oldstack = NtCurrentTeb()->cur_stack;
165 NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
166 0xff00 - sizeof(STACK16FRAME));
168 TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
169 pModule->self,hf,segnum );
170 DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
171 0, FALSE, DUPLICATE_SAME_ACCESS );
172 hFile16 = Win32HandleToDosFileHandle( hFile32 );
173 pSeg->hSeg = NE_CallTo16_word_www( selfloadheader->LoadAppSeg,
174 pModule->self, hFile16, segnum );
175 TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
176 _lclose16( hFile16 );
177 NtCurrentTeb()->cur_stack = oldstack;
179 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
180 ReadFile(hf, mem, size, &res, NULL);
183 The following bit of code for "iterated segments" was written without
184 any documentation on the format of these segments. It seems to work,
185 but may be missing something. If you have any doc please either send
186 it to me or fix the code yourself. gfm@werple.mira.net.au
188 char* buff = HeapAlloc(GetProcessHeap(), 0, size);
192 WARN_(dll)("Memory exausted!");
196 ReadFile(hf, buff, size, &res, NULL);
197 while(curr < buff + size) {
198 unsigned int rept = *((short*) curr)++;
199 unsigned int len = *((short*) curr)++;
200 for(; rept > 0; rept--) {
203 for(byte = 0; byte < len; byte++)
208 HeapFree(GetProcessHeap(), 0, buff);
211 pSeg->flags |= NE_SEGFLAGS_LOADED;
213 /* Perform exported function prolog fixups */
214 NE_FixupSegmentPrologs( pModule, segnum );
216 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
217 goto succeed; /* No relocation data, we are done */
219 ReadFile(hf, &count, sizeof(count), &res, NULL);
220 if (!count) goto succeed;
222 TRACE_(fixup)("Fixups for %.*s, segment %d, hSeg %04x\n",
223 *((BYTE *)pModule + pModule->name_table),
224 (char *)pModule + pModule->name_table + 1,
225 segnum, pSeg->hSeg );
226 TRACE_(segment)("Fixups for %.*s, segment %d, hSeg %04x\n",
227 *((BYTE *)pModule + pModule->name_table),
228 (char *)pModule + pModule->name_table + 1,
229 segnum, pSeg->hSeg );
231 reloc_entries = (struct relocation_entry_s *)HeapAlloc(GetProcessHeap(), 0, count * sizeof(struct relocation_entry_s));
232 if(reloc_entries == NULL) {
233 WARN_(fixup)("Not enough memory for relocation entries!");
236 if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
237 (res != count * sizeof(struct relocation_entry_s)))
239 WARN_(fixup)("Unable to read relocation information\n" );
244 * Go through the relocation table one entry at a time.
247 for (i = 0; i < count; i++, rep++)
250 * Get the target address corresponding to this entry.
253 /* If additive, there is no target chain list. Instead, add source
255 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
256 rep->relocation_type &= 0x3;
258 switch (rep->relocation_type)
260 case NE_RELTYPE_ORDINAL:
261 module = pModuleTable[rep->target1-1];
262 ordinal = rep->target2;
263 address = NE_GetEntryPoint( module, ordinal );
266 NE_MODULE *pTarget = NE_GetPtr( module );
268 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
269 module, rep->target1,
270 *((BYTE *)pModule + pModule->name_table),
271 *((BYTE *)pModule + pModule->name_table),
272 (char *)pModule + pModule->name_table + 1 );
275 ERR_(fixup)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
276 *((BYTE *)pTarget + pTarget->name_table),
277 (char *)pTarget + pTarget->name_table + 1,
279 address = (FARPROC16)0xdeadbeef;
284 NE_MODULE *pTarget = NE_GetPtr( module );
285 TRACE_(fixup)("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
286 *((BYTE *)pTarget + pTarget->name_table),
287 (char *)pTarget + pTarget->name_table + 1,
288 ordinal, HIWORD(address), LOWORD(address),
289 NE_GetRelocAddrName( rep->address_type, additive ) );
293 case NE_RELTYPE_NAME:
294 module = pModuleTable[rep->target1-1];
295 func_name = (char *)pModule + pModule->import_table + rep->target2;
296 memcpy( buffer, func_name+1, *func_name );
297 buffer[*func_name] = '\0';
299 ordinal = NE_GetOrdinal( module, func_name );
300 address = NE_GetEntryPoint( module, ordinal );
302 if (ERR_ON(fixup) && !address)
304 NE_MODULE *pTarget = NE_GetPtr( module );
305 ERR_(fixup)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
306 *((BYTE *)pTarget + pTarget->name_table),
307 (char *)pTarget + pTarget->name_table + 1, func_name );
309 if (!address) address = (FARPROC16) 0xdeadbeef;
312 NE_MODULE *pTarget = NE_GetPtr( module );
313 TRACE_(fixup)("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
314 *((BYTE *)pTarget + pTarget->name_table),
315 (char *)pTarget + pTarget->name_table + 1,
316 func_name, HIWORD(address), LOWORD(address),
317 NE_GetRelocAddrName( rep->address_type, additive ) );
321 case NE_RELTYPE_INTERNAL:
322 if ((rep->target1 & 0xff) == 0xff)
324 address = NE_GetEntryPoint( pModule->self, rep->target2 );
328 address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
331 TRACE_(fixup)("%d: %04x:%04x %s\n",
332 i + 1, HIWORD(address), LOWORD(address),
333 NE_GetRelocAddrName( rep->address_type, additive ) );
336 case NE_RELTYPE_OSFIXUP:
337 /* Relocation type 7:
339 * These appear to be used as fixups for the Windows
340 * floating point emulator. Let's just ignore them and
341 * try to use the hardware floating point. Linux should
342 * successfully emulate the coprocessor if it doesn't
345 TRACE_(fixup)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
346 i + 1, rep->relocation_type, rep->offset,
347 rep->target1, rep->target2,
348 NE_GetRelocAddrName( rep->address_type, additive ) );
352 offset = rep->offset;
354 /* Apparently, high bit of address_type is sometimes set; */
355 /* we ignore it for now */
356 if (rep->address_type > NE_RADDR_OFFSET32)
359 GetModuleName16( pModule->self, module, sizeof(module) );
360 ERR_(fixup)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
361 module, rep->address_type );
366 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
367 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
368 switch (rep->address_type & 0x7f)
370 case NE_RADDR_LOWBYTE:
371 *(BYTE *)sp += LOBYTE((int)address);
373 case NE_RADDR_OFFSET16:
374 *sp += LOWORD(address);
376 case NE_RADDR_POINTER32:
377 *sp += LOWORD(address);
378 *(sp+1) = HIWORD(address);
380 case NE_RADDR_SELECTOR:
381 /* Borland creates additive records with offset zero. Strange, but OK */
383 ERR_(fixup)("Additive selector to %04x.Please report\n",*sp);
385 *sp = HIWORD(address);
391 else /* non-additive fixup */
395 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
397 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
398 switch (rep->address_type & 0x7f)
400 case NE_RADDR_LOWBYTE:
401 *(BYTE *)sp = LOBYTE((int)address);
403 case NE_RADDR_OFFSET16:
404 *sp = LOWORD(address);
406 case NE_RADDR_POINTER32:
407 *(FARPROC16 *)sp = address;
409 case NE_RADDR_SELECTOR:
410 *sp = SELECTOROF(address);
415 if (next_offset == offset) break; /* avoid infinite loop */
416 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
417 offset = next_offset;
418 } while (offset != 0xffff);
422 HeapFree(GetProcessHeap(), 0, reloc_entries);
429 WARN_(fixup)("WARNING: %d: unknown ADDR TYPE %d, "
430 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
431 i + 1, rep->address_type, rep->relocation_type,
432 rep->offset, rep->target1, rep->target2);
433 HeapFree(GetProcessHeap(), 0, reloc_entries);
441 /***********************************************************************
444 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
447 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
449 if (pModule->flags & NE_FFLAGS_SELFLOAD)
454 /* Handle self-loading modules */
455 SELFLOADHEADER *selfloadheader;
456 HMODULE16 mod = GetModuleHandle16("KERNEL");
459 TRACE_(module)("%.*s is a self-loading module!\n",
460 *((BYTE*)pModule + pModule->name_table),
461 (char *)pModule + pModule->name_table + 1);
462 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
463 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) );
464 selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc");
465 selfloadheader->MyAlloc = GetProcAddress16(mod,"MyAlloc");
466 selfloadheader->SetOwner = GetProcAddress16(mod,"FarSetOwner");
467 sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 );
468 pModule->self_loading_sel = SEL(sel);
469 FarSetOwner16( sel, pModule->self );
470 oldstack = NtCurrentTeb()->cur_stack;
471 NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
472 0xff00 - sizeof(STACK16FRAME) );
474 hf = NE_OpenFile(pModule);
475 hFile16 = Win32HandleToDosFileHandle( hf );
476 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
477 pModule->self,hFile16);
478 NE_CallTo16_word_ww(selfloadheader->BootApp, pModule->self,hFile16);
479 TRACE_(dll)("Return from CallBootAppProc\n");
481 NtCurrentTeb()->cur_stack = oldstack;
483 for (i = 2; i <= pModule->seg_count; i++)
484 if (!NE_LoadSegment( pModule, i )) return FALSE;
488 for (i = 1; i <= pModule->seg_count; i++)
489 if (!NE_LoadSegment( pModule, i )) return FALSE;
495 /***********************************************************************
496 * NE_FixupSegmentPrologs
498 * Fixup exported functions prologs of one segment
500 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
502 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
505 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
508 TRACE_(module)("(%d);\n", segnum);
510 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
512 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
516 if (!pModule->dgroup) return;
518 if (!(dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg))) return;
520 pSeg = MapSL( MAKESEGPTR(sel, 0) );
522 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);
525 TRACE_(module)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
526 if (!(num_entries = bundle->last - bundle->first))
528 entry = (ET_ENTRY *)((BYTE *)bundle+6);
529 while (num_entries--)
531 /*TRACE_(module)("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
532 if (entry->segnum == segnum)
534 pFunc = ((BYTE *)pSeg+entry->offs);
535 TRACE_(module)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
536 if (*(pFunc+2) == 0x90)
538 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
540 TRACE_(module)("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
541 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
544 if (*(WORD *)pFunc == 0xd88c)
546 if ((entry->flags & 2)) /* public data ? */
548 TRACE_(module)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
549 *pFunc = 0xb8; /* mov ax, */
550 *(WORD *)(pFunc+1) = dgroup;
553 if ((pModule->flags & NE_FFLAGS_MULTIPLEDATA)
554 && (entry->flags & 1)) /* exported ? */
556 TRACE_(module)("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
557 *(WORD *)pFunc = 0x9090; /* nop, nop */
564 } while ( (bundle->next)
565 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
569 /***********************************************************************
570 * PatchCodeHandle (KERNEL.110)
572 * Needed for self-loading modules.
574 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
577 WORD sel = SEL(hSeg);
578 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
579 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
581 TRACE_(module)("(%04x);\n", hSeg);
583 /* find the segment number of the module that belongs to hSeg */
584 for (segnum = 1; segnum <= pModule->seg_count; segnum++)
586 if (SEL(pSegTable[segnum-1].hSeg) == sel)
588 NE_FixupSegmentPrologs(pModule, segnum);
593 return MAKELONG(hSeg, sel);
597 /***********************************************************************
598 * NE_GetDLLInitParams
600 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
601 WORD *hInst, WORD *ds, WORD *heap )
603 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
605 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
607 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
610 ERR_(dll)("Library is not marked SINGLEDATA\n");
613 else /* DATA NONE DLL */
619 else /* DATA SINGLE DLL */
621 if (pModule->dgroup) {
622 *ds = SEL(pSegTable[pModule->dgroup-1].hSeg);
623 *heap = pModule->heap_size;
625 else /* hmm, DLL has no dgroup,
626 but why has it NE_FFLAGS_SINGLEDATA set ?
627 Buggy DLL compiler ? */
634 *hInst = *ds ? GlobalHandle16(*ds) : pModule->self;
638 /***********************************************************************
641 * Call the DLL initialization code
643 static BOOL NE_InitDLL( NE_MODULE *pModule )
645 SEGTABLEENTRY *pSegTable;
646 WORD hInst, ds, heap;
649 pSegTable = NE_SEG_TABLE( pModule );
651 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
652 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
654 /* Call USER signal handler for Win3.1 compatibility. */
655 TASK_CallTaskSignalProc( USIG16_DLL_LOAD, pModule->self );
657 if (!pModule->cs) return TRUE; /* no initialization code */
660 /* Registers at initialization must be:
662 * di library instance
663 * ds data segment if any
664 * es:si command line (always 0)
667 memset( &context, 0, sizeof(context) );
669 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
674 context.SegEs = ds; /* who knows ... */
676 context.SegCs = SEL(pSegTable[pModule->cs-1].hSeg);
677 context.Eip = pModule->ip;
678 context.Ebp = OFFSETOF(NtCurrentTeb()->cur_stack) + (WORD)&((STACK16FRAME*)0)->bp;
681 pModule->cs = 0; /* Don't initialize it twice */
682 TRACE_(dll)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
683 context.SegCs, context.Eip, context.SegDs,
684 LOWORD(context.Edi), LOWORD(context.Ecx) );
685 wine_call_to_16_regs_short( &context, 0 );
689 /***********************************************************************
692 * Recursively initialize all DLLs (according to the order in which
693 * they where loaded).
695 void NE_InitializeDLLs( HMODULE16 hModule )
700 if (!(pModule = NE_GetPtr( hModule ))) return;
701 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
703 if (pModule->dlls_to_init)
705 HGLOBAL16 to_init = pModule->dlls_to_init;
706 pModule->dlls_to_init = 0;
707 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
709 NE_InitializeDLLs( *pDLL );
711 GlobalFree16( to_init );
713 NE_InitDLL( pModule );
717 /***********************************************************************
718 * NE_CallDllEntryPoint
720 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
722 typedef DWORD (WINAPI *WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
724 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
726 WORD hInst, ds, heap;
727 FARPROC16 entryPoint;
729 if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) return;
730 if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
731 if (!(entryPoint = GetProcAddress16( pModule->self, "DllEntryPoint" ))) return;
733 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
735 TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
736 NE_MODULE_NAME( pModule ),
737 SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
739 if ( pModule->flags & NE_FFLAGS_BUILTIN )
741 WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target;
743 entryProc( dwReason, hInst, ds, heap, 0, 0 );
747 LPBYTE stack = (LPBYTE)CURRENT_STACK16;
750 memset( &context, 0, sizeof(context) );
752 context.SegEs = ds; /* who knows ... */
754 context.SegCs = HIWORD(entryPoint);
755 context.Eip = LOWORD(entryPoint);
756 context.Ebp = OFFSETOF( NtCurrentTeb()->cur_stack )
757 + (WORD)&((STACK16FRAME*)0)->bp;
759 *(DWORD *)(stack - 4) = dwReason; /* dwReason */
760 *(WORD *) (stack - 6) = hInst; /* hInst */
761 *(WORD *) (stack - 8) = ds; /* wDS */
762 *(WORD *) (stack - 10) = heap; /* wHeapSize */
763 *(DWORD *)(stack - 14) = 0; /* dwReserved1 */
764 *(WORD *) (stack - 16) = 0; /* wReserved2 */
766 wine_call_to_16_regs_short( &context, 16 );
770 /***********************************************************************
771 * NE_DllProcessAttach
773 * Call the DllEntryPoint of all modules this one (recursively)
774 * depends on, according to the order in which they were loaded.
776 * Note that --as opposed to the PE module case-- there is no notion
777 * of 'module loaded into a process' for NE modules, and hence we
778 * have no place to store the fact that the DllEntryPoint of a
779 * given module was already called on behalf of this process (e.g.
780 * due to some earlier LoadLibrary16 call).
782 * Thus, we just call the DllEntryPoint twice in that case. Win9x
783 * appears to behave this way as well ...
785 * This routine must only be called with the Win16Lock held.
787 * FIXME: We should actually abort loading in case the DllEntryPoint
799 static void add_to_init_list( struct ne_init_list *list, NE_MODULE *hModule )
801 if ( list->count == list->size )
803 int newSize = list->size + 128;
804 NE_MODULE **newModule = HeapReAlloc( GetProcessHeap(), 0,
805 list->module, newSize*sizeof(NE_MODULE *) );
808 FIXME_(dll)("Out of memory!");
812 list->module = newModule;
813 list->size = newSize;
816 list->module[list->count++] = hModule;
819 static void free_init_list( struct ne_init_list *list )
823 HeapFree( GetProcessHeap(), 0, list->module );
824 memset( list, 0, sizeof(*list) );
828 static void fill_init_list( struct ne_init_list *list, HMODULE16 hModule )
834 if (!(pModule = NE_GetPtr( hModule ))) return;
835 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
837 /* Never add a module twice */
838 for ( i = 0; i < list->count; i++ )
839 if ( list->module[i] == pModule )
842 /* Check for recursive call */
843 if ( pModule->misc_flags & 0x80 ) return;
845 TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
847 /* Tag current module to prevent recursive loop */
848 pModule->misc_flags |= 0x80;
850 /* Recursively attach all DLLs this one depends on */
851 pModRef = NE_MODULE_TABLE( pModule );
852 for ( i = 0; i < pModule->modref_count; i++ )
854 fill_init_list( list, (HMODULE16)pModRef[i] );
856 /* Add current module */
857 add_to_init_list( list, pModule );
859 /* Remove recursion flag */
860 pModule->misc_flags &= ~0x80;
862 TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
865 static void call_init_list( struct ne_init_list *list )
868 for ( i = 0; i < list->count; i++ )
869 NE_CallDllEntryPoint( list->module[i], DLL_PROCESS_ATTACH );
872 void NE_DllProcessAttach( HMODULE16 hModule )
874 struct ne_init_list list;
875 memset( &list, 0, sizeof(list) );
877 fill_init_list( &list, hModule );
878 call_init_list( &list );
879 free_init_list( &list );
883 /***********************************************************************
886 * This function translates NE segment flags to GlobalAlloc flags
888 static WORD NE_Ne2MemFlags(WORD flags)
892 if (flags & NE_SEGFLAGS_DISCARDABLE)
893 memflags |= GMEM_DISCARDABLE;
894 if (flags & NE_SEGFLAGS_MOVEABLE ||
895 ( ! (flags & NE_SEGFLAGS_DATA) &&
896 ! (flags & NE_SEGFLAGS_LOADED) &&
897 ! (flags & NE_SEGFLAGS_ALLOCATED)
900 memflags |= GMEM_MOVEABLE;
901 memflags |= GMEM_ZEROINIT;
903 memflags = GMEM_ZEROINIT | GMEM_FIXED;
908 /***********************************************************************
909 * MyAlloc (KERNEL.668) Wine-specific export
911 * MyAlloc() function for self-loading apps.
913 DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
915 WORD size = wSize << wElem;
918 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
919 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
921 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
922 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
924 WORD hSel = SEL(hMem);
925 WORD access = SelectorAccessRights16(hSel,0,0);
927 access |= 2<<2; /* SEGMENT_CODE */
928 SelectorAccessRights16(hSel,1,access);
931 return MAKELONG( hMem, SEL(hMem) );
933 return MAKELONG( 0, hMem );
936 /***********************************************************************
939 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
941 if ( !pModule->dgroup )
942 return pModule->self;
946 pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
951 /***********************************************************************
954 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
956 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
958 unsigned char selflags;
960 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
962 if ( segnum < 1 || segnum > pModule->seg_count )
965 if ( (pModule->flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
966 return TRUE; /* selfloader allocates segment itself */
968 if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->dgroup )
969 return TRUE; /* all but DGROUP only allocated once */
971 minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
972 if ( segnum == pModule->ss ) minsize += pModule->stack_size;
973 if ( segnum == pModule->dgroup ) minsize += pModule->heap_size;
975 selflags = (pSeg->flags & NE_SEGFLAGS_DATA) ? WINE_LDT_FLAGS_DATA : WINE_LDT_FLAGS_CODE;
976 if (pSeg->flags & NE_SEGFLAGS_32BIT) selflags |= WINE_LDT_FLAGS_32BIT;
977 pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags), minsize, pModule->self, selflags );
978 if (!pSeg->hSeg) return FALSE;
980 pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
984 /***********************************************************************
985 * NE_CreateAllSegments
987 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
990 for ( i = 1; i <= pModule->seg_count; i++ )
991 if ( !NE_CreateSegment( pModule, i ) )
994 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
995 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
1000 /**********************************************************************
1001 * IsSharedSelector (KERNEL.345)
1003 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
1005 /* Check whether the selector belongs to a DLL */
1006 NE_MODULE *pModule = NE_GetPtr( selector );
1007 if (!pModule) return FALSE;
1008 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;