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 NE_MODULE **newModule = NULL;
828 if ( list->count == list->size )
830 int newSize = list->size + 128;
833 newModule = HeapReAlloc( GetProcessHeap(), 0,
834 list->module, newSize*sizeof(NE_MODULE *) );
836 newModule = HeapAlloc( GetProcessHeap(), 0,
837 newSize*sizeof(NE_MODULE *) );
840 FIXME_(dll)("Out of memory!");
844 list->module = newModule;
845 list->size = newSize;
848 list->module[list->count++] = hModule;
851 static void free_init_list( struct ne_init_list *list )
855 HeapFree( GetProcessHeap(), 0, list->module );
856 memset( list, 0, sizeof(*list) );
860 static void fill_init_list( struct ne_init_list *list, HMODULE16 hModule )
866 if (!(pModule = NE_GetPtr( hModule ))) return;
867 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
869 /* Never add a module twice */
870 for ( i = 0; i < list->count; i++ )
871 if ( list->module[i] == pModule )
874 /* Check for recursive call */
875 if ( pModule->misc_flags & 0x80 ) return;
877 TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
879 /* Tag current module to prevent recursive loop */
880 pModule->misc_flags |= 0x80;
882 /* Recursively attach all DLLs this one depends on */
883 pModRef = NE_MODULE_TABLE( pModule );
884 for ( i = 0; i < pModule->modref_count; i++ )
886 fill_init_list( list, (HMODULE16)pModRef[i] );
888 /* Add current module */
889 add_to_init_list( list, pModule );
891 /* Remove recursion flag */
892 pModule->misc_flags &= ~0x80;
894 TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
897 static void call_init_list( struct ne_init_list *list )
900 for ( i = 0; i < list->count; i++ )
901 NE_CallDllEntryPoint( list->module[i], DLL_PROCESS_ATTACH );
904 void NE_DllProcessAttach( HMODULE16 hModule )
906 struct ne_init_list list;
907 memset( &list, 0, sizeof(list) );
909 fill_init_list( &list, hModule );
910 call_init_list( &list );
911 free_init_list( &list );
915 /***********************************************************************
918 * This function translates NE segment flags to GlobalAlloc flags
920 static WORD NE_Ne2MemFlags(WORD flags)
924 if (flags & NE_SEGFLAGS_DISCARDABLE)
925 memflags |= GMEM_DISCARDABLE;
926 if (flags & NE_SEGFLAGS_MOVEABLE ||
927 ( ! (flags & NE_SEGFLAGS_DATA) &&
928 ! (flags & NE_SEGFLAGS_LOADED) &&
929 ! (flags & NE_SEGFLAGS_ALLOCATED)
932 memflags |= GMEM_MOVEABLE;
933 memflags |= GMEM_ZEROINIT;
935 memflags = GMEM_ZEROINIT | GMEM_FIXED;
940 /***********************************************************************
941 * MyAlloc (KERNEL.668) Wine-specific export
943 * MyAlloc() function for self-loading apps.
945 DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
947 WORD size = wSize << wElem;
950 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
951 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
953 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
954 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
956 WORD hSel = SEL(hMem);
957 WORD access = SelectorAccessRights16(hSel,0,0);
959 access |= 2<<2; /* SEGMENT_CODE */
960 SelectorAccessRights16(hSel,1,access);
963 return MAKELONG( hMem, SEL(hMem) );
965 return MAKELONG( 0, hMem );
968 /***********************************************************************
971 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
973 if ( !pModule->dgroup )
974 return pModule->self;
978 pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
983 /***********************************************************************
986 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
988 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
990 unsigned char selflags;
992 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
994 if ( segnum < 1 || segnum > pModule->seg_count )
997 if ( (pModule->flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
998 return TRUE; /* selfloader allocates segment itself */
1000 if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->dgroup )
1001 return TRUE; /* all but DGROUP only allocated once */
1003 minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
1004 if ( segnum == pModule->ss ) minsize += pModule->stack_size;
1005 if ( segnum == pModule->dgroup ) minsize += pModule->heap_size;
1007 selflags = (pSeg->flags & NE_SEGFLAGS_DATA) ? WINE_LDT_FLAGS_DATA : WINE_LDT_FLAGS_CODE;
1008 if (pSeg->flags & NE_SEGFLAGS_32BIT) selflags |= WINE_LDT_FLAGS_32BIT;
1009 pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags), minsize, pModule->self, selflags );
1010 if (!pSeg->hSeg) return FALSE;
1012 pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
1016 /***********************************************************************
1017 * NE_CreateAllSegments
1019 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
1022 for ( i = 1; i <= pModule->seg_count; i++ )
1023 if ( !NE_CreateSegment( pModule, i ) )
1026 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
1027 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
1032 /**********************************************************************
1033 * IsSharedSelector (KERNEL.345)
1035 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
1037 /* Check whether the selector belongs to a DLL */
1038 NE_MODULE *pModule = NE_GetPtr( selector );
1039 if (!pModule) return FALSE;
1040 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;