Avoid gratuitously changing the ZORDER.
[wine.git] / loader / ne / segment.c
blob6da63719ecb7638ad486c3fbf52aaa1bfd063beb
1 /*
2 * NE segment loading
4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
6 */
8 #include <assert.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 #include <ctype.h>
16 #include <string.h>
17 #include <errno.h>
19 #include "wine/winbase16.h"
20 #include "neexe.h"
21 #include "global.h"
22 #include "task.h"
23 #include "selectors.h"
24 #include "callback.h"
25 #include "file.h"
26 #include "module.h"
27 #include "stackframe.h"
28 #include "builtin16.h"
29 #include "debugtools.h"
30 #include "toolhelp.h"
32 DECLARE_DEBUG_CHANNEL(dll)
33 DECLARE_DEBUG_CHANNEL(fixup)
34 DECLARE_DEBUG_CHANNEL(module)
35 DECLARE_DEBUG_CHANNEL(segment)
37 #define SEL(x) ((x)|1)
39 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);
41 /***********************************************************************
42 * NE_GetRelocAddrName
44 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
46 switch(addr_type & 0x7f)
48 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
49 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
50 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
51 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
52 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
53 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
55 return "???";
59 /***********************************************************************
60 * NE_LoadSegment
62 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
64 SEGTABLEENTRY *pSegTable, *pSeg;
65 WORD *pModuleTable;
66 WORD count, i, offset, next_offset;
67 HMODULE16 module;
68 FARPROC16 address = 0;
69 HFILE hf;
70 DWORD res;
71 struct relocation_entry_s *rep, *reloc_entries;
72 BYTE *func_name;
73 int size;
74 char* mem;
76 char buffer[256];
77 int ordinal, additive;
78 unsigned short *sp;
80 pSegTable = NE_SEG_TABLE( pModule );
81 pSeg = pSegTable + segnum - 1;
83 if (pSeg->flags & NE_SEGFLAGS_LOADED)
85 /* self-loader ? -> already loaded it */
86 if (pModule->flags & NE_FFLAGS_SELFLOAD)
87 return TRUE;
89 /* leave, except for DGROUP, as this may be the second instance */
90 if (segnum != pModule->dgroup)
91 return TRUE;
94 if (!pSeg->filepos) return TRUE; /* No file image, just return */
96 pModuleTable = NE_MODULE_TABLE( pModule );
98 hf = NE_OpenFile( pModule );
99 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
100 segnum, pSeg->hSeg, pSeg->flags );
101 SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
102 if (pSeg->size) size = pSeg->size;
103 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
104 mem = GlobalLock16(pSeg->hSeg);
105 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
107 /* Implement self-loading segments */
108 SELFLOADHEADER *selfloadheader;
109 DWORD oldstack;
110 HFILE hFile32;
111 HFILE16 hFile16;
113 selfloadheader = (SELFLOADHEADER *)
114 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg),0);
115 oldstack = NtCurrentTeb()->cur_stack;
116 NtCurrentTeb()->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
117 0xff00 - sizeof(STACK16FRAME));
119 TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
120 pModule->self,hf,segnum );
121 DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
122 0, FALSE, DUPLICATE_SAME_ACCESS );
123 hFile16 = FILE_AllocDosHandle( hFile32 );
124 pSeg->hSeg = Callbacks->CallLoadAppSegProc( selfloadheader->LoadAppSeg,
125 pModule->self, hFile16,
126 segnum );
127 TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
128 _lclose16( hFile16 );
129 NtCurrentTeb()->cur_stack = oldstack;
131 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
132 ReadFile(hf, mem, size, &res, NULL);
133 else {
135 The following bit of code for "iterated segments" was written without
136 any documentation on the format of these segments. It seems to work,
137 but may be missing something. If you have any doc please either send
138 it to me or fix the code yourself. gfm@werple.mira.net.au
140 char* buff = HeapAlloc(GetProcessHeap(), 0, size);
141 char* curr = buff;
143 if(buff == NULL) {
144 WARN_(dll)("Memory exausted!");
145 return FALSE;
148 ReadFile(hf, buff, size, &res, NULL);
149 while(curr < buff + size) {
150 unsigned int rept = *((short*) curr)++;
151 unsigned int len = *((short*) curr)++;
152 for(; rept > 0; rept--) {
153 char* bytes = curr;
154 unsigned int byte;
155 for(byte = 0; byte < len; byte++)
156 *mem++ = *bytes++;
158 curr += len;
160 HeapFree(GetProcessHeap(), 0, buff);
163 pSeg->flags |= NE_SEGFLAGS_LOADED;
165 /* Perform exported function prolog fixups */
166 NE_FixupSegmentPrologs( pModule, segnum );
168 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
169 return TRUE; /* No relocation data, we are done */
171 ReadFile(hf, &count, sizeof(count), &res, NULL);
172 if (!count) return TRUE;
174 TRACE_(fixup)("Fixups for %.*s, segment %d, hSeg %04x\n",
175 *((BYTE *)pModule + pModule->name_table),
176 (char *)pModule + pModule->name_table + 1,
177 segnum, pSeg->hSeg );
178 TRACE_(segment)("Fixups for %.*s, segment %d, hSeg %04x\n",
179 *((BYTE *)pModule + pModule->name_table),
180 (char *)pModule + pModule->name_table + 1,
181 segnum, pSeg->hSeg );
183 reloc_entries = (struct relocation_entry_s *)HeapAlloc(GetProcessHeap(), 0, count * sizeof(struct relocation_entry_s));
184 if(reloc_entries == NULL) {
185 WARN_(fixup)("Not enough memory for relocation entries!");
186 return FALSE;
188 if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
189 (res != count * sizeof(struct relocation_entry_s)))
191 WARN_(fixup)("Unable to read relocation information\n" );
192 return FALSE;
196 * Go through the relocation table one entry at a time.
198 rep = reloc_entries;
199 for (i = 0; i < count; i++, rep++)
202 * Get the target address corresponding to this entry.
205 /* If additive, there is no target chain list. Instead, add source
206 and target */
207 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
208 rep->relocation_type &= 0x3;
210 switch (rep->relocation_type)
212 case NE_RELTYPE_ORDINAL:
213 module = pModuleTable[rep->target1-1];
214 ordinal = rep->target2;
215 address = NE_GetEntryPoint( module, ordinal );
216 if (!address)
218 NE_MODULE *pTarget = NE_GetPtr( module );
219 if (!pTarget)
220 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
221 module, rep->target1,
222 *((BYTE *)pModule + pModule->name_table),
223 *((BYTE *)pModule + pModule->name_table),
224 (char *)pModule + pModule->name_table + 1 );
225 else
227 ERR_(fixup)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
228 *((BYTE *)pTarget + pTarget->name_table),
229 (char *)pTarget + pTarget->name_table + 1,
230 ordinal );
231 address = (FARPROC16)0xdeadbeef;
234 if (TRACE_ON(fixup))
236 NE_MODULE *pTarget = NE_GetPtr( module );
237 TRACE_(fixup)("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
238 *((BYTE *)pTarget + pTarget->name_table),
239 (char *)pTarget + pTarget->name_table + 1,
240 ordinal, HIWORD(address), LOWORD(address),
241 NE_GetRelocAddrName( rep->address_type, additive ) );
243 break;
245 case NE_RELTYPE_NAME:
246 module = pModuleTable[rep->target1-1];
247 func_name = (char *)pModule + pModule->import_table + rep->target2;
248 memcpy( buffer, func_name+1, *func_name );
249 buffer[*func_name] = '\0';
250 func_name = buffer;
251 ordinal = NE_GetOrdinal( module, func_name );
252 address = NE_GetEntryPoint( module, ordinal );
254 if (ERR_ON(fixup) && !address)
256 NE_MODULE *pTarget = NE_GetPtr( module );
257 ERR_(fixup)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
258 *((BYTE *)pTarget + pTarget->name_table),
259 (char *)pTarget + pTarget->name_table + 1, func_name );
261 if (!address) address = (FARPROC16) 0xdeadbeef;
262 if (TRACE_ON(fixup))
264 NE_MODULE *pTarget = NE_GetPtr( module );
265 TRACE_(fixup)("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
266 *((BYTE *)pTarget + pTarget->name_table),
267 (char *)pTarget + pTarget->name_table + 1,
268 func_name, HIWORD(address), LOWORD(address),
269 NE_GetRelocAddrName( rep->address_type, additive ) );
271 break;
273 case NE_RELTYPE_INTERNAL:
274 if ((rep->target1 & 0xff) == 0xff)
276 address = NE_GetEntryPoint( pModule->self, rep->target2 );
278 else
280 address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
283 TRACE_(fixup)("%d: %04x:%04x %s\n",
284 i + 1, HIWORD(address), LOWORD(address),
285 NE_GetRelocAddrName( rep->address_type, additive ) );
286 break;
288 case NE_RELTYPE_OSFIXUP:
289 /* Relocation type 7:
291 * These appear to be used as fixups for the Windows
292 * floating point emulator. Let's just ignore them and
293 * try to use the hardware floating point. Linux should
294 * successfully emulate the coprocessor if it doesn't
295 * exist.
297 TRACE_(fixup)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
298 i + 1, rep->relocation_type, rep->offset,
299 rep->target1, rep->target2,
300 NE_GetRelocAddrName( rep->address_type, additive ) );
301 continue;
304 offset = rep->offset;
306 /* Apparently, high bit of address_type is sometimes set; */
307 /* we ignore it for now */
308 if (rep->address_type > NE_RADDR_OFFSET32)
310 char module[10];
311 GetModuleName16( pModule->self, module, sizeof(module) );
312 ERR_(fixup)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
313 module, rep->address_type );
316 if (additive)
318 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
319 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
320 switch (rep->address_type & 0x7f)
322 case NE_RADDR_LOWBYTE:
323 *(BYTE *)sp += LOBYTE((int)address);
324 break;
325 case NE_RADDR_OFFSET16:
326 *sp += LOWORD(address);
327 break;
328 case NE_RADDR_POINTER32:
329 *sp += LOWORD(address);
330 *(sp+1) = HIWORD(address);
331 break;
332 case NE_RADDR_SELECTOR:
333 /* Borland creates additive records with offset zero. Strange, but OK */
334 if (*sp)
335 ERR_(fixup)("Additive selector to %04x.Please report\n",*sp);
336 else
337 *sp = HIWORD(address);
338 break;
339 default:
340 goto unknown;
343 else /* non-additive fixup */
347 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
348 next_offset = *sp;
349 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
350 switch (rep->address_type & 0x7f)
352 case NE_RADDR_LOWBYTE:
353 *(BYTE *)sp = LOBYTE((int)address);
354 break;
355 case NE_RADDR_OFFSET16:
356 *sp = LOWORD(address);
357 break;
358 case NE_RADDR_POINTER32:
359 *(FARPROC16 *)sp = address;
360 break;
361 case NE_RADDR_SELECTOR:
362 *sp = SELECTOROF(address);
363 break;
364 default:
365 goto unknown;
367 if (next_offset == offset) break; /* avoid infinite loop */
368 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
369 offset = next_offset;
370 } while (offset != 0xffff);
374 HeapFree(GetProcessHeap(), 0, reloc_entries);
375 return TRUE;
377 unknown:
378 WARN_(fixup)("WARNING: %d: unknown ADDR TYPE %d, "
379 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
380 i + 1, rep->address_type, rep->relocation_type,
381 rep->offset, rep->target1, rep->target2);
382 HeapFree(GetProcessHeap(), 0, reloc_entries);
383 return FALSE;
387 /***********************************************************************
388 * NE_LoadAllSegments
390 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
392 int i;
393 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
395 if (pModule->flags & NE_FFLAGS_SELFLOAD)
397 HFILE hf;
398 HFILE16 hFile16;
399 /* Handle self-loading modules */
400 SELFLOADHEADER *selfloadheader;
401 HMODULE16 hselfload = GetModuleHandle16("WPROCS");
402 DWORD oldstack;
404 TRACE_(module)("%.*s is a self-loading module!\n",
405 *((BYTE*)pModule + pModule->name_table),
406 (char *)pModule + pModule->name_table + 1);
407 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
408 selfloadheader = (SELFLOADHEADER *)
409 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg), 0);
410 selfloadheader->EntryAddrProc = NE_GetEntryPoint(hselfload,27);
411 selfloadheader->MyAlloc = NE_GetEntryPoint(hselfload,28);
412 selfloadheader->SetOwner = NE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
413 pModule->self_loading_sel = SEL(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
414 oldstack = NtCurrentTeb()->cur_stack;
415 NtCurrentTeb()->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
416 0xff00 - sizeof(STACK16FRAME) );
418 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule),
419 GetCurrentProcess(), &hf, 0, FALSE, DUPLICATE_SAME_ACCESS );
420 hFile16 = FILE_AllocDosHandle( hf );
421 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
422 pModule->self,hFile16);
423 Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self,hFile16);
424 TRACE_(dll)("Return from CallBootAppProc\n");
425 _lclose16(hf);
426 NtCurrentTeb()->cur_stack = oldstack;
428 for (i = 2; i <= pModule->seg_count; i++)
429 if (!NE_LoadSegment( pModule, i )) return FALSE;
431 else
433 for (i = 1; i <= pModule->seg_count; i++)
434 if (!NE_LoadSegment( pModule, i )) return FALSE;
436 return TRUE;
440 /***********************************************************************
441 * NE_FixupSegmentPrologs
443 * Fixup exported functions prologs of one segment
445 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
447 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
448 ET_BUNDLE *bundle;
449 ET_ENTRY *entry;
450 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
451 BYTE *pSeg, *pFunc;
453 TRACE_(module)("(%d);\n", segnum);
455 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
457 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
458 return;
461 if (!pModule->dgroup) return;
463 if (!(dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg))) return;
465 pSeg = PTR_SEG_OFF_TO_LIN(sel, 0);
467 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);
469 do {
470 TRACE_(module)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
471 if (!(num_entries = bundle->last - bundle->first))
472 return;
473 entry = (ET_ENTRY *)((BYTE *)bundle+6);
474 while (num_entries--)
476 /*TRACE(module, "entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
477 if (entry->segnum == segnum)
479 pFunc = ((BYTE *)pSeg+entry->offs);
480 TRACE_(module)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
481 if (*(pFunc+2) == 0x90)
483 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
485 TRACE_(module)("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
486 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
489 if (*(WORD *)pFunc == 0xd88c)
491 if ((entry->flags & 2)) /* public data ? */
493 TRACE_(module)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
494 *pFunc = 0xb8; /* mov ax, */
495 *(WORD *)(pFunc+1) = dgroup;
497 else
498 if ((pModule->flags & NE_FFLAGS_MULTIPLEDATA)
499 && (entry->flags & 1)) /* exported ? */
501 TRACE_(module)("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
502 *(WORD *)pFunc = 0x9090; /* nop, nop */
507 entry++;
509 } while ( (bundle->next)
510 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
514 /***********************************************************************
515 * PatchCodeHandle
517 * Needed for self-loading modules.
519 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
521 WORD segnum;
522 WORD sel = SEL(hSeg);
523 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
524 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
526 TRACE_(module)("(%04x);\n", hSeg);
528 /* find the segment number of the module that belongs to hSeg */
529 for (segnum = 1; segnum <= pModule->seg_count; segnum++)
531 if (SEL(pSegTable[segnum-1].hSeg) == sel)
533 NE_FixupSegmentPrologs(pModule, segnum);
534 break;
538 return MAKELONG(hSeg, sel);
542 /***********************************************************************
543 * NE_GetDLLInitParams
545 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
546 WORD *hInst, WORD *ds, WORD *heap )
548 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
550 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
552 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
554 /* Not SINGLEDATA */
555 ERR_(dll)("Library is not marked SINGLEDATA\n");
556 exit(1);
558 else /* DATA NONE DLL */
560 *ds = 0;
561 *heap = 0;
564 else /* DATA SINGLE DLL */
566 if (pModule->dgroup) {
567 *ds = SEL(pSegTable[pModule->dgroup-1].hSeg);
568 *heap = pModule->heap_size;
570 else /* hmm, DLL has no dgroup,
571 but why has it NE_FFLAGS_SINGLEDATA set ?
572 Buggy DLL compiler ? */
574 *ds = 0;
575 *heap = 0;
579 *hInst = *ds ? GlobalHandle16(*ds) : pModule->self;
583 /***********************************************************************
584 * NE_InitDLL
586 * Call the DLL initialization code
588 static BOOL NE_InitDLL( TDB* pTask, NE_MODULE *pModule )
590 SEGTABLEENTRY *pSegTable;
591 WORD hInst, ds, heap;
592 CONTEXT86 context;
594 pSegTable = NE_SEG_TABLE( pModule );
596 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
597 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
599 /* Call USER signal handler for Win3.1 compatibility. */
600 TASK_CallTaskSignalProc( USIG16_DLL_LOAD, pModule->self );
602 if (!pModule->cs) return TRUE; /* no initialization code */
605 /* Registers at initialization must be:
606 * cx heap size
607 * di library instance
608 * ds data segment if any
609 * es:si command line (always 0)
612 memset( &context, 0, sizeof(context) );
614 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
616 ECX_reg(&context) = heap;
617 EDI_reg(&context) = hInst;
618 DS_reg(&context) = ds;
619 ES_reg(&context) = ds; /* who knows ... */
621 CS_reg(&context) = SEL(pSegTable[pModule->cs-1].hSeg);
622 EIP_reg(&context) = pModule->ip;
623 EBP_reg(&context) = OFFSETOF(NtCurrentTeb()->cur_stack) + (WORD)&((STACK16FRAME*)0)->bp;
626 pModule->cs = 0; /* Don't initialize it twice */
627 TRACE_(dll)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
628 CS_reg(&context), EIP_reg(&context), DS_reg(&context),
629 DI_reg(&context), CX_reg(&context) );
630 Callbacks->CallRegisterShortProc( &context, 0 );
631 return TRUE;
634 /***********************************************************************
635 * NE_InitializeDLLs
637 * Recursively initialize all DLLs (according to the order in which
638 * they where loaded).
640 void NE_InitializeDLLs( HMODULE16 hModule )
642 TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
643 NE_MODULE *pModule;
644 HMODULE16 *pDLL;
646 if (!(pModule = NE_GetPtr( hModule ))) return;
647 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
649 if (pModule->dlls_to_init)
651 HGLOBAL16 to_init = pModule->dlls_to_init;
652 pModule->dlls_to_init = 0;
653 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
655 NE_InitializeDLLs( *pDLL );
657 GlobalFree16( to_init );
659 NE_InitDLL( pTask, pModule );
663 /***********************************************************************
664 * NE_CallDllEntryPoint
666 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
668 typedef DWORD WINAPI (*WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
670 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
672 WORD hInst, ds, heap;
673 FARPROC16 entryPoint;
674 WORD ordinal;
676 if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) return;
677 if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
678 if (!(ordinal = NE_GetOrdinal( pModule->self, "DllEntryPoint" ))) return;
679 if (!(entryPoint = NE_GetEntryPoint( pModule->self, ordinal ))) return;
681 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
683 TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
684 NE_MODULE_NAME( pModule ),
685 SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
687 if ( pModule->flags & NE_FFLAGS_BUILTIN )
689 WinNEEntryProc entryProc = (WinNEEntryProc)
690 ((ENTRYPOINT16 *)PTR_SEG_TO_LIN( entryPoint ))->target;
692 entryProc( dwReason, hInst, ds, heap, 0, 0 );
694 else
696 LPBYTE stack = (LPBYTE)CURRENT_STACK16;
697 CONTEXT86 context;
699 memset( &context, 0, sizeof(context) );
700 DS_reg(&context) = ds;
701 ES_reg(&context) = ds; /* who knows ... */
703 CS_reg(&context) = HIWORD(entryPoint);
704 EIP_reg(&context) = LOWORD(entryPoint);
705 EBP_reg(&context) = OFFSETOF( NtCurrentTeb()->cur_stack )
706 + (WORD)&((STACK16FRAME*)0)->bp;
708 *(DWORD *)(stack - 4) = dwReason; /* dwReason */
709 *(WORD *) (stack - 6) = hInst; /* hInst */
710 *(WORD *) (stack - 8) = ds; /* wDS */
711 *(WORD *) (stack - 10) = heap; /* wHeapSize */
712 *(DWORD *)(stack - 14) = 0; /* dwReserved1 */
713 *(WORD *) (stack - 16) = 0; /* wReserved2 */
715 Callbacks->CallRegisterShortProc( &context, 16 );
719 /***********************************************************************
720 * NE_DllProcessAttach
722 * Call the DllEntryPoint of all modules this one (recursively)
723 * depends on, according to the order in which they were loaded.
725 * Note that --as opposed to the PE module case-- there is no notion
726 * of 'module loaded into a process' for NE modules, and hence we
727 * have no place to store the fact that the DllEntryPoint of a
728 * given module was already called on behalf of this process (e.g.
729 * due to some earlier LoadLibrary16 call).
731 * Thus, we just call the DllEntryPoint twice in that case. Win9x
732 * appears to behave this way as well ...
734 * This routine must only be called with the Win16Lock held.
736 * FIXME: We should actually abort loading in case the DllEntryPoint
737 * returns FALSE ...
740 void NE_DllProcessAttach( HMODULE16 hModule )
742 NE_MODULE *pModule;
743 WORD *pModRef;
744 int i;
746 if (!(pModule = NE_GetPtr( hModule ))) return;
747 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
749 /* Check for recursive call */
750 if ( pModule->misc_flags & 0x80 ) return;
752 TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
754 /* Tag current module to prevent recursive loop */
755 pModule->misc_flags |= 0x80;
757 /* Recursively attach all DLLs this one depends on */
758 pModRef = NE_MODULE_TABLE( pModule );
759 for ( i = 0; i < pModule->modref_count; i++ )
760 if ( pModRef[i] )
761 NE_DllProcessAttach( (HMODULE16)pModRef[i] );
763 /* Call DLL entry point */
764 NE_CallDllEntryPoint( pModule, DLL_PROCESS_ATTACH );
766 /* Remove recursion flag */
767 pModule->misc_flags &= ~0x80;
769 TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
773 /***********************************************************************
774 * NE_Ne2MemFlags
776 * This function translates NE segment flags to GlobalAlloc flags
778 static WORD NE_Ne2MemFlags(WORD flags)
780 WORD memflags = 0;
781 #if 1
782 if (flags & NE_SEGFLAGS_DISCARDABLE)
783 memflags |= GMEM_DISCARDABLE;
784 if (flags & NE_SEGFLAGS_MOVEABLE ||
785 ( ! (flags & NE_SEGFLAGS_DATA) &&
786 ! (flags & NE_SEGFLAGS_LOADED) &&
787 ! (flags & NE_SEGFLAGS_ALLOCATED)
790 memflags |= GMEM_MOVEABLE;
791 memflags |= GMEM_ZEROINIT;
792 #else
793 memflags = GMEM_ZEROINIT | GMEM_FIXED;
794 #endif
795 return memflags;
798 /***********************************************************************
799 * NE_AllocateSegment (WPROCS.26)
801 * MyAlloc() function for self-loading apps.
803 DWORD WINAPI NE_AllocateSegment( WORD wFlags, WORD wSize, WORD wElem )
805 WORD size = wSize << wElem;
806 HANDLE16 hMem = 0;
808 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
809 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
811 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
812 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
814 WORD hSel = SEL(hMem);
815 WORD access = SelectorAccessRights16(hSel,0,0);
817 access |= 2<<2; /* SEGMENT_CODE */
818 SelectorAccessRights16(hSel,1,access);
820 if (size)
821 return MAKELONG( hMem, SEL(hMem) );
822 else
823 return MAKELONG( 0, hMem );
826 /***********************************************************************
827 * NE_GetInstance
829 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
831 if ( !pModule->dgroup )
832 return pModule->self;
833 else
835 SEGTABLEENTRY *pSeg;
836 pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
837 return pSeg->hSeg;
841 /***********************************************************************
842 * NE_CreateSegment
844 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
846 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
847 int minsize;
849 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
851 if ( segnum < 1 || segnum > pModule->seg_count )
852 return FALSE;
854 if ( (pModule->flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
855 return TRUE; /* selfloader allocates segment itself */
857 if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->dgroup )
858 return TRUE; /* all but DGROUP only allocated once */
860 minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
861 if ( segnum == pModule->ss ) minsize += pModule->stack_size;
862 if ( segnum == pModule->dgroup ) minsize += pModule->heap_size;
864 pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags),
865 minsize, pModule->self,
866 !(pSeg->flags & NE_SEGFLAGS_DATA),
867 (pSeg->flags & NE_SEGFLAGS_32BIT) != 0,
868 FALSE /*pSeg->flags & NE_SEGFLAGS_READONLY*/ );
869 if (!pSeg->hSeg) return FALSE;
871 pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
872 return TRUE;
875 /***********************************************************************
876 * NE_CreateAllSegments
878 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
880 int i;
881 for ( i = 1; i <= pModule->seg_count; i++ )
882 if ( !NE_CreateSegment( pModule, i ) )
883 return FALSE;
885 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
886 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
887 return TRUE;
891 /**********************************************************************
892 * IsSharedSelector (KERNEL.345)
894 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
896 /* Check whether the selector belongs to a DLL */
897 NE_MODULE *pModule = NE_GetPtr( selector );
898 if (!pModule) return FALSE;
899 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;