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"
38 #include "wine/library.h"
43 #include "stackframe.h"
44 #include "builtin16.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(fixup);
48 WINE_DECLARE_DEBUG_CHANNEL(dll);
49 WINE_DECLARE_DEBUG_CHANNEL(module);
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);
87 /***********************************************************************
90 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
92 switch(addr_type & 0x7f)
94 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
95 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
96 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
97 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
98 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
99 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
105 /***********************************************************************
108 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
110 SEGTABLEENTRY *pSegTable, *pSeg;
112 WORD count, i, offset, next_offset;
114 FARPROC16 address = 0;
117 struct relocation_entry_s *rep, *reloc_entries;
123 int ordinal, additive;
126 pSegTable = NE_SEG_TABLE( pModule );
127 pSeg = pSegTable + segnum - 1;
129 if (pSeg->flags & NE_SEGFLAGS_LOADED)
131 /* self-loader ? -> already loaded it */
132 if (pModule->flags & NE_FFLAGS_SELFLOAD)
135 /* leave, except for DGROUP, as this may be the second instance */
136 if (segnum != pModule->dgroup)
140 if (!pSeg->filepos) return TRUE; /* No file image, just return */
142 pModuleTable = NE_MODULE_TABLE( pModule );
144 hf = NE_OpenFile( pModule );
145 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
146 segnum, pSeg->hSeg, pSeg->flags );
147 SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
148 if (pSeg->size) size = pSeg->size;
149 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
150 mem = GlobalLock16(pSeg->hSeg);
151 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
153 /* Implement self-loading segments */
154 SELFLOADHEADER *selfloadheader;
161 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
162 oldstack = NtCurrentTeb()->cur_stack;
163 NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
164 0xff00 - sizeof(STACK16FRAME));
166 TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=%p,segnum=%d\n",
167 pModule->self,hf,segnum );
168 DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
169 0, FALSE, DUPLICATE_SAME_ACCESS );
170 hFile16 = Win32HandleToDosFileHandle( hFile32 );
171 args[2] = pModule->self;
174 WOWCallback16Ex( (DWORD)selfloadheader->LoadAppSeg, WCB16_PASCAL, sizeof(args), args, &ret );
175 pSeg->hSeg = LOWORD(ret);
176 TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
177 _lclose16( hFile16 );
178 NtCurrentTeb()->cur_stack = oldstack;
180 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
181 ReadFile(hf, mem, size, &res, NULL);
184 The following bit of code for "iterated segments" was written without
185 any documentation on the format of these segments. It seems to work,
186 but may be missing something. If you have any doc please either send
187 it to me or fix the code yourself. gfm@werple.mira.net.au
189 char* buff = HeapAlloc(GetProcessHeap(), 0, size);
193 WARN_(dll)("Memory exausted!");
197 ReadFile(hf, buff, size, &res, NULL);
198 while(curr < buff + size) {
199 unsigned int rept = *((short*) curr)++;
200 unsigned int len = *((short*) curr)++;
201 for(; rept > 0; rept--) {
204 for(byte = 0; byte < len; byte++)
209 HeapFree(GetProcessHeap(), 0, buff);
212 pSeg->flags |= NE_SEGFLAGS_LOADED;
214 /* Perform exported function prolog fixups */
215 NE_FixupSegmentPrologs( pModule, segnum );
217 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
218 goto succeed; /* No relocation data, we are done */
220 ReadFile(hf, &count, sizeof(count), &res, NULL);
221 if (!count) goto succeed;
223 TRACE("Fixups for %.*s, segment %d, hSeg %04x\n",
224 *((BYTE *)pModule + pModule->name_table),
225 (char *)pModule + pModule->name_table + 1,
226 segnum, pSeg->hSeg );
228 reloc_entries = (struct relocation_entry_s *)HeapAlloc(GetProcessHeap(), 0, count * sizeof(struct relocation_entry_s));
229 if(reloc_entries == NULL) {
230 WARN("Not enough memory for relocation entries!");
233 if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
234 (res != count * sizeof(struct relocation_entry_s)))
236 WARN("Unable to read relocation information\n" );
241 * Go through the relocation table one entry at a time.
244 for (i = 0; i < count; i++, rep++)
247 * Get the target address corresponding to this entry.
250 /* If additive, there is no target chain list. Instead, add source
252 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
253 rep->relocation_type &= 0x3;
255 switch (rep->relocation_type)
257 case NE_RELTYPE_ORDINAL:
258 module = pModuleTable[rep->target1-1];
259 ordinal = rep->target2;
260 address = NE_GetEntryPoint( module, ordinal );
263 NE_MODULE *pTarget = NE_GetPtr( module );
265 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
266 module, rep->target1,
267 *((BYTE *)pModule + pModule->name_table),
268 *((BYTE *)pModule + pModule->name_table),
269 (char *)pModule + pModule->name_table + 1 );
272 ERR("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
273 *((BYTE *)pTarget + pTarget->name_table),
274 (char *)pTarget + pTarget->name_table + 1,
276 address = (FARPROC16)0xdeadbeef;
281 NE_MODULE *pTarget = NE_GetPtr( module );
282 TRACE("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
283 *((BYTE *)pTarget + pTarget->name_table),
284 (char *)pTarget + pTarget->name_table + 1,
285 ordinal, HIWORD(address), LOWORD(address),
286 NE_GetRelocAddrName( rep->address_type, additive ) );
290 case NE_RELTYPE_NAME:
291 module = pModuleTable[rep->target1-1];
292 func_name = (char *)pModule + pModule->import_table + rep->target2;
293 memcpy( buffer, func_name+1, *func_name );
294 buffer[*func_name] = '\0';
296 ordinal = NE_GetOrdinal( module, func_name );
297 address = NE_GetEntryPoint( module, ordinal );
299 if (ERR_ON(fixup) && !address)
301 NE_MODULE *pTarget = NE_GetPtr( module );
302 ERR("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
303 *((BYTE *)pTarget + pTarget->name_table),
304 (char *)pTarget + pTarget->name_table + 1, func_name );
306 if (!address) address = (FARPROC16) 0xdeadbeef;
309 NE_MODULE *pTarget = NE_GetPtr( module );
310 TRACE("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
311 *((BYTE *)pTarget + pTarget->name_table),
312 (char *)pTarget + pTarget->name_table + 1,
313 func_name, HIWORD(address), LOWORD(address),
314 NE_GetRelocAddrName( rep->address_type, additive ) );
318 case NE_RELTYPE_INTERNAL:
319 if ((rep->target1 & 0xff) == 0xff)
321 address = NE_GetEntryPoint( pModule->self, rep->target2 );
325 address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
328 TRACE("%d: %04x:%04x %s\n",
329 i + 1, HIWORD(address), LOWORD(address),
330 NE_GetRelocAddrName( rep->address_type, additive ) );
333 case NE_RELTYPE_OSFIXUP:
334 /* Relocation type 7:
336 * These appear to be used as fixups for the Windows
337 * floating point emulator. Let's just ignore them and
338 * try to use the hardware floating point. Linux should
339 * successfully emulate the coprocessor if it doesn't
342 TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
343 i + 1, rep->relocation_type, rep->offset,
344 rep->target1, rep->target2,
345 NE_GetRelocAddrName( rep->address_type, additive ) );
349 offset = rep->offset;
351 /* Apparently, high bit of address_type is sometimes set; */
352 /* we ignore it for now */
353 if (rep->address_type > NE_RADDR_OFFSET32)
356 GetModuleName16( pModule->self, module, sizeof(module) );
357 ERR("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
358 module, rep->address_type );
363 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
364 TRACE(" %04x:%04x\n", offset, *sp );
365 switch (rep->address_type & 0x7f)
367 case NE_RADDR_LOWBYTE:
368 *(BYTE *)sp += LOBYTE((int)address);
370 case NE_RADDR_OFFSET16:
371 *sp += LOWORD(address);
373 case NE_RADDR_POINTER32:
374 *sp += LOWORD(address);
375 *(sp+1) = HIWORD(address);
377 case NE_RADDR_SELECTOR:
378 /* Borland creates additive records with offset zero. Strange, but OK */
380 ERR("Additive selector to %04x.Please report\n",*sp);
382 *sp = HIWORD(address);
388 else /* non-additive fixup */
392 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
394 TRACE(" %04x:%04x\n", offset, *sp );
395 switch (rep->address_type & 0x7f)
397 case NE_RADDR_LOWBYTE:
398 *(BYTE *)sp = LOBYTE((int)address);
400 case NE_RADDR_OFFSET16:
401 *sp = LOWORD(address);
403 case NE_RADDR_POINTER32:
404 *(FARPROC16 *)sp = address;
406 case NE_RADDR_SELECTOR:
407 *sp = SELECTOROF(address);
412 if (next_offset == offset) break; /* avoid infinite loop */
413 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
414 offset = next_offset;
415 } while (offset != 0xffff);
419 HeapFree(GetProcessHeap(), 0, reloc_entries);
426 WARN("WARNING: %d: unknown ADDR TYPE %d, "
427 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
428 i + 1, rep->address_type, rep->relocation_type,
429 rep->offset, rep->target1, rep->target2);
430 HeapFree(GetProcessHeap(), 0, reloc_entries);
438 /***********************************************************************
441 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
444 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
446 if (pModule->flags & NE_FFLAGS_SELFLOAD)
451 /* Handle self-loading modules */
452 SELFLOADHEADER *selfloadheader;
453 HMODULE16 mod = GetModuleHandle16("KERNEL");
457 TRACE_(module)("%.*s is a self-loading module!\n",
458 *((BYTE*)pModule + pModule->name_table),
459 (char *)pModule + pModule->name_table + 1);
460 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
461 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) );
462 selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc");
463 selfloadheader->MyAlloc = GetProcAddress16(mod,"MyAlloc");
464 selfloadheader->SetOwner = GetProcAddress16(mod,"FarSetOwner");
465 sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 );
466 pModule->self_loading_sel = SEL(sel);
467 FarSetOwner16( sel, pModule->self );
468 oldstack = NtCurrentTeb()->cur_stack;
469 NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
470 0xff00 - sizeof(STACK16FRAME) );
472 hf = NE_OpenFile(pModule);
473 hFile16 = Win32HandleToDosFileHandle( hf );
474 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
475 pModule->self,hFile16);
476 args[1] = pModule->self;
478 WOWCallback16Ex( (DWORD)selfloadheader->BootApp, WCB16_PASCAL, sizeof(args), args, NULL );
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("(%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("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("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("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("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("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("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 NE_CallUserSignalProc( pModule->self, USIG16_DLL_LOAD );
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 WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)&context );
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_CallUserSignalProc
720 * According to "Undocumented Windows", the task signal proc is
721 * bypassed for module load/unload notifications, and the USER signal
722 * proc is called directly instead. This is what this function does.
724 typedef DWORD (WINAPI *pSignalProc)( HANDLE16 module, UINT16 code, UINT16 exit,
725 HINSTANCE16 inst, HQUEUE16 queue );
727 void NE_CallUserSignalProc( HMODULE16 hModule, UINT16 code )
730 HMODULE16 user = GetModuleHandle16("user.exe");
733 if ((proc = GetProcAddress16( user, "SignalProc" )))
735 /* USER is always a builtin dll */
736 pSignalProc sigproc = (pSignalProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)proc ))->target;
737 sigproc( hModule, code, 0, 0, 0 );
742 /***********************************************************************
743 * NE_CallDllEntryPoint
745 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
747 typedef DWORD (WINAPI *WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
749 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
751 WORD hInst, ds, heap;
752 FARPROC16 entryPoint;
754 if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) return;
755 if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
756 if (!(entryPoint = GetProcAddress16( pModule->self, "DllEntryPoint" ))) return;
758 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
760 TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
761 NE_MODULE_NAME( pModule ),
762 SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
764 if ( pModule->flags & NE_FFLAGS_BUILTIN )
766 WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target;
768 entryProc( dwReason, hInst, ds, heap, 0, 0 );
775 memset( &context, 0, sizeof(context) );
777 context.SegEs = ds; /* who knows ... */
779 context.SegCs = HIWORD(entryPoint);
780 context.Eip = LOWORD(entryPoint);
781 context.Ebp = OFFSETOF( NtCurrentTeb()->cur_stack )
782 + (WORD)&((STACK16FRAME*)0)->bp;
784 args[7] = HIWORD(dwReason);
785 args[6] = LOWORD(dwReason);
789 args[2] = 0; /* HIWORD(dwReserved1) */
790 args[1] = 0; /* LOWORD(dwReserved1) */
791 args[0] = 0; /* wReserved2 */
792 WOWCallback16Ex( 0, WCB16_REGS, sizeof(args), args, (DWORD *)&context );
796 /***********************************************************************
797 * NE_DllProcessAttach
799 * Call the DllEntryPoint of all modules this one (recursively)
800 * depends on, according to the order in which they were loaded.
802 * Note that --as opposed to the PE module case-- there is no notion
803 * of 'module loaded into a process' for NE modules, and hence we
804 * have no place to store the fact that the DllEntryPoint of a
805 * given module was already called on behalf of this process (e.g.
806 * due to some earlier LoadLibrary16 call).
808 * Thus, we just call the DllEntryPoint twice in that case. Win9x
809 * appears to behave this way as well ...
811 * This routine must only be called with the Win16Lock held.
813 * FIXME: We should actually abort loading in case the DllEntryPoint
825 static void add_to_init_list( struct ne_init_list *list, NE_MODULE *hModule )
827 if ( list->count == list->size )
829 int newSize = list->size + 128;
830 NE_MODULE **newModule = HeapReAlloc( GetProcessHeap(), 0,
831 list->module, newSize*sizeof(NE_MODULE *) );
834 FIXME_(dll)("Out of memory!");
838 list->module = newModule;
839 list->size = newSize;
842 list->module[list->count++] = hModule;
845 static void free_init_list( struct ne_init_list *list )
849 HeapFree( GetProcessHeap(), 0, list->module );
850 memset( list, 0, sizeof(*list) );
854 static void fill_init_list( struct ne_init_list *list, HMODULE16 hModule )
860 if (!(pModule = NE_GetPtr( hModule ))) return;
861 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
863 /* Never add a module twice */
864 for ( i = 0; i < list->count; i++ )
865 if ( list->module[i] == pModule )
868 /* Check for recursive call */
869 if ( pModule->misc_flags & 0x80 ) return;
871 TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
873 /* Tag current module to prevent recursive loop */
874 pModule->misc_flags |= 0x80;
876 /* Recursively attach all DLLs this one depends on */
877 pModRef = NE_MODULE_TABLE( pModule );
878 for ( i = 0; i < pModule->modref_count; i++ )
880 fill_init_list( list, (HMODULE16)pModRef[i] );
882 /* Add current module */
883 add_to_init_list( list, pModule );
885 /* Remove recursion flag */
886 pModule->misc_flags &= ~0x80;
888 TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
891 static void call_init_list( struct ne_init_list *list )
894 for ( i = 0; i < list->count; i++ )
895 NE_CallDllEntryPoint( list->module[i], DLL_PROCESS_ATTACH );
898 void NE_DllProcessAttach( HMODULE16 hModule )
900 struct ne_init_list list;
901 memset( &list, 0, sizeof(list) );
903 fill_init_list( &list, hModule );
904 call_init_list( &list );
905 free_init_list( &list );
909 /***********************************************************************
912 * This function translates NE segment flags to GlobalAlloc flags
914 static WORD NE_Ne2MemFlags(WORD flags)
918 if (flags & NE_SEGFLAGS_DISCARDABLE)
919 memflags |= GMEM_DISCARDABLE;
920 if (flags & NE_SEGFLAGS_MOVEABLE ||
921 ( ! (flags & NE_SEGFLAGS_DATA) &&
922 ! (flags & NE_SEGFLAGS_LOADED) &&
923 ! (flags & NE_SEGFLAGS_ALLOCATED)
926 memflags |= GMEM_MOVEABLE;
927 memflags |= GMEM_ZEROINIT;
929 memflags = GMEM_ZEROINIT | GMEM_FIXED;
934 /***********************************************************************
935 * MyAlloc (KERNEL.668) Wine-specific export
937 * MyAlloc() function for self-loading apps.
939 DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
941 WORD size = wSize << wElem;
944 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
945 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
947 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
948 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
950 WORD hSel = SEL(hMem);
951 WORD access = SelectorAccessRights16(hSel,0,0);
953 access |= 2<<2; /* SEGMENT_CODE */
954 SelectorAccessRights16(hSel,1,access);
957 return MAKELONG( hMem, SEL(hMem) );
959 return MAKELONG( 0, hMem );
962 /***********************************************************************
965 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
967 if ( !pModule->dgroup )
968 return pModule->self;
972 pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
977 /***********************************************************************
980 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
982 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
984 unsigned char selflags;
986 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
988 if ( segnum < 1 || segnum > pModule->seg_count )
991 if ( (pModule->flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
992 return TRUE; /* selfloader allocates segment itself */
994 if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->dgroup )
995 return TRUE; /* all but DGROUP only allocated once */
997 minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
998 if ( segnum == pModule->ss ) minsize += pModule->stack_size;
999 if ( segnum == pModule->dgroup ) minsize += pModule->heap_size;
1001 selflags = (pSeg->flags & NE_SEGFLAGS_DATA) ? WINE_LDT_FLAGS_DATA : WINE_LDT_FLAGS_CODE;
1002 if (pSeg->flags & NE_SEGFLAGS_32BIT) selflags |= WINE_LDT_FLAGS_32BIT;
1003 pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags), minsize, pModule->self, selflags );
1004 if (!pSeg->hSeg) return FALSE;
1006 pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
1010 /***********************************************************************
1011 * NE_CreateAllSegments
1013 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
1016 for ( i = 1; i <= pModule->seg_count; i++ )
1017 if ( !NE_CreateSegment( pModule, i ) )
1020 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
1021 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
1026 /**********************************************************************
1027 * IsSharedSelector (KERNEL.345)
1029 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
1031 /* Check whether the selector belongs to a DLL */
1032 NE_MODULE *pModule = NE_GetPtr( selector );
1033 if (!pModule) return FALSE;
1034 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;