Don't create thunk for task signal proc, call it directly.
[wine/wine-kai.git] / loader / ne / segment.c
blob698343852651796d8ab57b3291478c3d2c4b0fc0
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 "debugtools.h"
29 #include "xmalloc.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 /***********************************************************************
40 * NE_GetRelocAddrName
42 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
44 switch(addr_type & 0x7f)
46 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
47 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
48 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
49 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
50 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
51 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
53 return "???";
57 /***********************************************************************
58 * NE_LoadSegment
60 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
62 SEGTABLEENTRY *pSegTable, *pSeg;
63 WORD *pModuleTable;
64 WORD count, i, offset, next_offset;
65 HMODULE16 module;
66 FARPROC16 address = 0;
67 HFILE hf;
68 DWORD res;
69 struct relocation_entry_s *rep, *reloc_entries;
70 BYTE *func_name;
71 int size;
72 char* mem;
74 char buffer[256];
75 int ordinal, additive;
76 unsigned short *sp;
78 pSegTable = NE_SEG_TABLE( pModule );
79 pSeg = pSegTable + segnum - 1;
81 if (pSeg->flags & NE_SEGFLAGS_LOADED) /* already loaded ? */
82 return TRUE;
84 if (!pSeg->filepos) return TRUE; /* No file image, just return */
86 pModuleTable = NE_MODULE_TABLE( pModule );
88 hf = NE_OpenFile( pModule );
89 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
90 segnum, pSeg->hSeg, pSeg->flags );
91 SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
92 if (pSeg->size) size = pSeg->size;
93 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
94 mem = GlobalLock16(pSeg->hSeg);
95 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
97 /* Implement self-loading segments */
98 SELFLOADHEADER *selfloadheader;
99 DWORD oldstack;
100 WORD old_hSeg, new_hSeg;
101 HFILE hFile32;
102 HFILE16 hFile16;
104 selfloadheader = (SELFLOADHEADER *)
105 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg),0);
106 oldstack = NtCurrentTeb()->cur_stack;
107 old_hSeg = pSeg->hSeg;
108 NtCurrentTeb()->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
109 0xff00 - sizeof(STACK16FRAME));
111 TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
112 pModule->self,hf,segnum );
113 DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
114 0, FALSE, DUPLICATE_SAME_ACCESS );
115 hFile16 = FILE_AllocDosHandle( hFile32 );
116 new_hSeg = Callbacks->CallLoadAppSegProc(selfloadheader->LoadAppSeg,
117 pModule->self, hFile16,
118 segnum );
119 TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n",new_hSeg);
120 _lclose16( hFile16 );
121 if (SEL(new_hSeg) != SEL(old_hSeg)) {
122 /* Self loaders like creating their own selectors;
123 * they love asking for trouble to Wine developers
125 if (segnum == pModule->dgroup) {
126 memcpy(PTR_SEG_OFF_TO_LIN(SEL(old_hSeg),0),
127 PTR_SEG_OFF_TO_LIN(SEL(new_hSeg),0),
128 pSeg->minsize ? pSeg->minsize : 0x10000);
129 FreeSelector16(SEL(new_hSeg));
130 pSeg->hSeg = old_hSeg;
131 TRACE_(module)("New hSeg allocated for dgroup segment:Old=%d,New=%d\n",
132 old_hSeg, new_hSeg);
133 } else {
134 FreeSelector16(SEL(pSeg->hSeg));
135 pSeg->hSeg = new_hSeg;
139 NtCurrentTeb()->cur_stack = oldstack;
141 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
142 ReadFile(hf, mem, size, &res, NULL);
143 else {
145 The following bit of code for "iterated segments" was written without
146 any documentation on the format of these segments. It seems to work,
147 but may be missing something. If you have any doc please either send
148 it to me or fix the code yourself. gfm@werple.mira.net.au
150 char* buff = xmalloc(size);
151 char* curr = buff;
152 ReadFile(hf, buff, size, &res, NULL);
153 while(curr < buff + size) {
154 unsigned int rept = *((short*) curr)++;
155 unsigned int len = *((short*) curr)++;
156 for(; rept > 0; rept--) {
157 char* bytes = curr;
158 unsigned int byte;
159 for(byte = 0; byte < len; byte++)
160 *mem++ = *bytes++;
162 curr += len;
164 free(buff);
167 pSeg->flags |= NE_SEGFLAGS_LOADED;
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 *)xmalloc(count * sizeof(struct relocation_entry_s));
184 if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
185 (res != count * sizeof(struct relocation_entry_s)))
187 WARN_(fixup)("Unable to read relocation information\n" );
188 return FALSE;
192 * Go through the relocation table one entry at a time.
194 rep = reloc_entries;
195 for (i = 0; i < count; i++, rep++)
198 * Get the target address corresponding to this entry.
201 /* If additive, there is no target chain list. Instead, add source
202 and target */
203 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
204 rep->relocation_type &= 0x3;
206 switch (rep->relocation_type)
208 case NE_RELTYPE_ORDINAL:
209 module = pModuleTable[rep->target1-1];
210 ordinal = rep->target2;
211 address = NE_GetEntryPoint( module, ordinal );
212 if (!address)
214 NE_MODULE *pTarget = NE_GetPtr( module );
215 if (!pTarget)
216 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
217 module, rep->target1,
218 *((BYTE *)pModule + pModule->name_table),
219 *((BYTE *)pModule + pModule->name_table),
220 (char *)pModule + pModule->name_table + 1 );
221 else
223 ERR_(fixup)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
224 *((BYTE *)pTarget + pTarget->name_table),
225 (char *)pTarget + pTarget->name_table + 1,
226 ordinal );
227 address = (FARPROC16)0xdeadbeef;
230 if (TRACE_ON(fixup))
232 NE_MODULE *pTarget = NE_GetPtr( module );
233 TRACE_(fixup)("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
234 *((BYTE *)pTarget + pTarget->name_table),
235 (char *)pTarget + pTarget->name_table + 1,
236 ordinal, HIWORD(address), LOWORD(address),
237 NE_GetRelocAddrName( rep->address_type, additive ) );
239 break;
241 case NE_RELTYPE_NAME:
242 module = pModuleTable[rep->target1-1];
243 func_name = (char *)pModule + pModule->import_table + rep->target2;
244 memcpy( buffer, func_name+1, *func_name );
245 buffer[*func_name] = '\0';
246 func_name = buffer;
247 ordinal = NE_GetOrdinal( module, func_name );
248 address = NE_GetEntryPoint( module, ordinal );
250 if (ERR_ON(fixup) && !address)
252 NE_MODULE *pTarget = NE_GetPtr( module );
253 ERR_(fixup)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
254 *((BYTE *)pTarget + pTarget->name_table),
255 (char *)pTarget + pTarget->name_table + 1, func_name );
257 if (!address) address = (FARPROC16) 0xdeadbeef;
258 if (TRACE_ON(fixup))
260 NE_MODULE *pTarget = NE_GetPtr( module );
261 TRACE_(fixup)("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
262 *((BYTE *)pTarget + pTarget->name_table),
263 (char *)pTarget + pTarget->name_table + 1,
264 func_name, HIWORD(address), LOWORD(address),
265 NE_GetRelocAddrName( rep->address_type, additive ) );
267 break;
269 case NE_RELTYPE_INTERNAL:
270 if ((rep->target1 & 0xff) == 0xff)
272 address = NE_GetEntryPoint( pModule->self, rep->target2 );
274 else
276 address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
279 TRACE_(fixup)("%d: %04x:%04x %s\n",
280 i + 1, HIWORD(address), LOWORD(address),
281 NE_GetRelocAddrName( rep->address_type, additive ) );
282 break;
284 case NE_RELTYPE_OSFIXUP:
285 /* Relocation type 7:
287 * These appear to be used as fixups for the Windows
288 * floating point emulator. Let's just ignore them and
289 * try to use the hardware floating point. Linux should
290 * successfully emulate the coprocessor if it doesn't
291 * exist.
293 TRACE_(fixup)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
294 i + 1, rep->relocation_type, rep->offset,
295 rep->target1, rep->target2,
296 NE_GetRelocAddrName( rep->address_type, additive ) );
297 continue;
300 offset = rep->offset;
302 /* Apparently, high bit of address_type is sometimes set; */
303 /* we ignore it for now */
304 if (rep->address_type > NE_RADDR_OFFSET32)
306 char module[10];
307 GetModuleName16( pModule->self, module, sizeof(module) );
308 ERR_(fixup)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
309 module, rep->address_type );
312 if (additive)
314 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
315 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
316 switch (rep->address_type & 0x7f)
318 case NE_RADDR_LOWBYTE:
319 *(BYTE *)sp += LOBYTE((int)address);
320 break;
321 case NE_RADDR_OFFSET16:
322 *sp += LOWORD(address);
323 break;
324 case NE_RADDR_POINTER32:
325 *sp += LOWORD(address);
326 *(sp+1) = HIWORD(address);
327 break;
328 case NE_RADDR_SELECTOR:
329 /* Borland creates additive records with offset zero. Strange, but OK */
330 if (*sp)
331 ERR_(fixup)("Additive selector to %04x.Please report\n",*sp);
332 else
333 *sp = HIWORD(address);
334 break;
335 default:
336 goto unknown;
339 else /* non-additive fixup */
343 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
344 next_offset = *sp;
345 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
346 switch (rep->address_type & 0x7f)
348 case NE_RADDR_LOWBYTE:
349 *(BYTE *)sp = LOBYTE((int)address);
350 break;
351 case NE_RADDR_OFFSET16:
352 *sp = LOWORD(address);
353 break;
354 case NE_RADDR_POINTER32:
355 *(FARPROC16 *)sp = address;
356 break;
357 case NE_RADDR_SELECTOR:
358 *sp = SELECTOROF(address);
359 break;
360 default:
361 goto unknown;
363 if (next_offset == offset) break; /* avoid infinite loop */
364 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
365 offset = next_offset;
366 } while (offset != 0xffff);
370 free(reloc_entries);
371 return TRUE;
373 unknown:
374 WARN_(fixup)("WARNING: %d: unknown ADDR TYPE %d, "
375 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
376 i + 1, rep->address_type, rep->relocation_type,
377 rep->offset, rep->target1, rep->target2);
378 free(reloc_entries);
379 return FALSE;
383 /***********************************************************************
384 * NE_LoadAllSegments
386 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
388 int i;
389 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
391 if (pModule->flags & NE_FFLAGS_SELFLOAD)
393 HFILE hf;
394 HFILE16 hFile16;
395 /* Handle self-loading modules */
396 SELFLOADHEADER *selfloadheader;
397 HMODULE16 hselfload = GetModuleHandle16("WPROCS");
398 DWORD oldstack;
399 WORD saved_hSeg = pSegTable[pModule->dgroup - 1].hSeg;
401 TRACE_(module)("%.*s is a self-loading module!\n",
402 *((BYTE*)pModule + pModule->name_table),
403 (char *)pModule + pModule->name_table + 1);
404 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
405 selfloadheader = (SELFLOADHEADER *)
406 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg), 0);
407 selfloadheader->EntryAddrProc = NE_GetEntryPoint(hselfload,27);
408 selfloadheader->MyAlloc = NE_GetEntryPoint(hselfload,28);
409 selfloadheader->SetOwner = NE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
410 pModule->self_loading_sel = SEL(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
411 oldstack = NtCurrentTeb()->cur_stack;
412 NtCurrentTeb()->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
413 0xff00 - sizeof(STACK16FRAME) );
415 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule),
416 GetCurrentProcess(), &hf, 0, FALSE, DUPLICATE_SAME_ACCESS );
417 hFile16 = FILE_AllocDosHandle( hf );
418 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
419 pModule->self,hFile16);
420 Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self,hFile16);
421 TRACE_(dll)("Return from CallBootAppProc\n");
422 _lclose16(hf);
423 /* some BootApp procs overwrite the segment handle of dgroup */
424 pSegTable[pModule->dgroup - 1].hSeg = saved_hSeg;
425 NtCurrentTeb()->cur_stack = oldstack;
427 for (i = 2; i <= pModule->seg_count; i++)
428 if (!NE_LoadSegment( pModule, i )) return FALSE;
430 else
432 for (i = 1; i <= pModule->seg_count; i++)
433 if (!NE_LoadSegment( pModule, i )) return FALSE;
435 return TRUE;
439 /***********************************************************************
440 * NE_FixupSegmentPrologs
442 * Fixup exported functions prologs of one segment
444 void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
446 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
447 ET_BUNDLE *bundle;
448 ET_ENTRY *entry;
449 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
450 BYTE *pSeg, *pFunc;
452 TRACE_(module)("(%d);\n", segnum);
454 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
456 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
457 return;
460 if (!pModule->dgroup) return;
462 if (!(dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg))) return;
464 pSeg = PTR_SEG_OFF_TO_LIN(sel, 0);
466 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);
468 do {
469 TRACE_(module)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
470 if (!(num_entries = bundle->last - bundle->first))
471 return;
472 entry = (ET_ENTRY *)((BYTE *)bundle+6);
473 while (num_entries--)
475 /*TRACE(module, "entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
476 if (entry->segnum == segnum)
478 pFunc = ((BYTE *)pSeg+entry->offs);
479 TRACE_(module)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
480 if (*(pFunc+2) == 0x90)
482 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
484 TRACE_(module)("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
485 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
488 if (*(WORD *)pFunc == 0xd88c)
490 if ((entry->flags & 2)) /* public data ? */
492 TRACE_(module)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
493 *pFunc = 0xb8; /* mov ax, */
494 *(WORD *)(pFunc+1) = dgroup;
496 else
497 if ((pModule->flags & NE_FFLAGS_MULTIPLEDATA)
498 && (entry->flags & 1)) /* exported ? */
500 TRACE_(module)("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
501 *(WORD *)pFunc = 0x9090; /* nop, nop */
506 entry++;
508 } while ( (bundle->next)
509 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
513 /***********************************************************************
514 * PatchCodeHandle
516 * Needed for self-loading modules.
518 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
520 WORD segnum;
521 WORD sel = SEL(hSeg);
522 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
523 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
525 TRACE_(module)("(%04x);\n", hSeg);
527 /* find the segment number of the module that belongs to hSeg */
528 for (segnum = 1; segnum <= pModule->seg_count; segnum++)
530 if (SEL(pSegTable[segnum-1].hSeg) == sel)
532 NE_FixupSegmentPrologs(pModule, segnum);
533 break;
537 return MAKELONG(hSeg, sel);
540 /***********************************************************************
541 * NE_FixupPrologs
543 * Fixup the exported functions prologs.
545 void NE_FixupPrologs( NE_MODULE *pModule )
547 WORD segnum;
549 TRACE_(module)("(%04x)\n", pModule->self );
551 if (pModule->flags & NE_FFLAGS_SELFLOAD)
552 NE_FixupSegmentPrologs(pModule, 1);
553 else
554 for (segnum=1; segnum <= pModule->seg_count; segnum++)
555 NE_FixupSegmentPrologs(pModule, segnum);
558 /***********************************************************************
559 * NE_GetDLLInitParams
561 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
562 WORD *hInst, WORD *ds, WORD *heap )
564 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
566 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
568 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
570 /* Not SINGLEDATA */
571 ERR_(dll)("Library is not marked SINGLEDATA\n");
572 exit(1);
574 else /* DATA NONE DLL */
576 *ds = 0;
577 *heap = 0;
580 else /* DATA SINGLE DLL */
582 if (pModule->dgroup) {
583 *ds = SEL(pSegTable[pModule->dgroup-1].hSeg);
584 *heap = pModule->heap_size;
586 else /* hmm, DLL has no dgroup,
587 but why has it NE_FFLAGS_SINGLEDATA set ?
588 Buggy DLL compiler ? */
590 *ds = 0;
591 *heap = 0;
595 *hInst = *ds ? *ds : pModule->self;
599 /***********************************************************************
600 * NE_InitDLL
602 * Call the DLL initialization code
604 static BOOL NE_InitDLL( TDB* pTask, NE_MODULE *pModule )
606 SEGTABLEENTRY *pSegTable;
607 WORD hInst, ds, heap;
608 CONTEXT86 context;
610 pSegTable = NE_SEG_TABLE( pModule );
612 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
613 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
615 /* Call USER signal handler for Win3.1 compatibility. */
616 TASK_CallTaskSignalProc( USIG16_DLL_LOAD, pModule->self );
618 if (!pModule->cs) return TRUE; /* no initialization code */
621 /* Registers at initialization must be:
622 * cx heap size
623 * di library instance
624 * ds data segment if any
625 * es:si command line (always 0)
628 memset( &context, 0, sizeof(context) );
630 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
632 ECX_reg(&context) = heap;
633 EDI_reg(&context) = hInst;
634 DS_reg(&context) = ds;
635 ES_reg(&context) = ds; /* who knows ... */
637 CS_reg(&context) = SEL(pSegTable[pModule->cs-1].hSeg);
638 EIP_reg(&context) = pModule->ip;
639 EBP_reg(&context) = OFFSETOF(NtCurrentTeb()->cur_stack) + (WORD)&((STACK16FRAME*)0)->bp;
642 pModule->cs = 0; /* Don't initialize it twice */
643 TRACE_(dll)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
644 CS_reg(&context), EIP_reg(&context), DS_reg(&context),
645 DI_reg(&context), CX_reg(&context) );
646 Callbacks->CallRegisterShortProc( &context, 0 );
647 return TRUE;
650 /***********************************************************************
651 * NE_CallDllEntryPoint
653 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
656 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
658 WORD hInst, ds, heap;
659 FARPROC16 entryPoint;
660 WORD ordinal;
661 CONTEXT86 context;
662 LPBYTE stack = (LPBYTE)CURRENT_STACK16;
664 if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
665 if (!(ordinal = NE_GetOrdinal( pModule->self, "DllEntryPoint" ))) return;
666 if (!(entryPoint = NE_GetEntryPoint( pModule->self, ordinal ))) return;
668 memset( &context, 0, sizeof(context) );
670 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
672 DS_reg(&context) = ds;
673 ES_reg(&context) = ds; /* who knows ... */
675 CS_reg(&context) = HIWORD(entryPoint);
676 EIP_reg(&context) = LOWORD(entryPoint);
677 EBP_reg(&context) = OFFSETOF( NtCurrentTeb()->cur_stack )
678 + (WORD)&((STACK16FRAME*)0)->bp;
680 *(DWORD *)(stack - 4) = dwReason; /* dwReason */
681 *(WORD *) (stack - 6) = hInst; /* hInst */
682 *(WORD *) (stack - 8) = ds; /* wDS */
683 *(WORD *) (stack - 10) = heap; /* wHeapSize */
684 *(DWORD *)(stack - 14) = 0; /* dwReserved1 */
685 *(WORD *) (stack - 16) = 0; /* wReserved2 */
687 TRACE_(dll)("Calling DllEntryPoint, cs:ip=%04lx:%04lx\n",
688 CS_reg(&context), EIP_reg(&context));
690 Callbacks->CallRegisterShortProc( &context, 16 );
694 /***********************************************************************
695 * NE_InitializeDLLs
697 * Recursively initialize all DLLs (according to the order in which
698 * they where loaded).
700 void NE_InitializeDLLs( HMODULE16 hModule )
702 TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
703 NE_MODULE *pModule;
704 HMODULE16 *pDLL;
706 if (!(pModule = NE_GetPtr( hModule ))) return;
707 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
709 if (pModule->dlls_to_init)
711 HGLOBAL16 to_init = pModule->dlls_to_init;
712 pModule->dlls_to_init = 0;
713 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
715 NE_InitializeDLLs( *pDLL );
717 GlobalFree16( to_init );
719 NE_InitDLL( pTask, pModule );
720 NE_CallDllEntryPoint( pModule, DLL_PROCESS_ATTACH );
724 /***********************************************************************
725 * NE_Ne2MemFlags
727 * This function translates NE segment flags to GlobalAlloc flags
729 static WORD NE_Ne2MemFlags(WORD flags)
731 WORD memflags = 0;
732 #if 1
733 if (flags & NE_SEGFLAGS_DISCARDABLE)
734 memflags |= GMEM_DISCARDABLE;
735 if (flags & NE_SEGFLAGS_MOVEABLE ||
736 ( ! (flags & NE_SEGFLAGS_DATA) &&
737 ! (flags & NE_SEGFLAGS_LOADED) &&
738 ! (flags & NE_SEGFLAGS_ALLOCATED)
741 memflags |= GMEM_MOVEABLE;
742 memflags |= GMEM_ZEROINIT;
743 #else
744 memflags = GMEM_ZEROINIT | GMEM_FIXED;
745 #endif
746 return memflags;
750 /***********************************************************************
751 * NE_CreateInstance
753 * If lib_only is TRUE, handle the module like a library even if it is a .EXE
755 HINSTANCE16 NE_CreateInstance( NE_MODULE *pModule, HINSTANCE16 *prev,
756 BOOL lib_only )
758 SEGTABLEENTRY *pSegment;
759 int minsize;
760 HINSTANCE16 hNewSeg;
762 if (pModule->dgroup == 0)
764 if (prev) *prev = pModule->self;
765 return pModule->self;
768 pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
769 if (prev) *prev = SEL(pSegment->hSeg);
771 /* if it's a library, create a new instance only the first time */
772 if (pSegment->hSeg)
774 if (pModule->flags & NE_FFLAGS_LIBMODULE) return SEL(pSegment->hSeg);
775 if (lib_only) return SEL(pSegment->hSeg);
778 minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
779 if (pModule->ss == pModule->dgroup) minsize += pModule->stack_size;
780 minsize += pModule->heap_size;
781 hNewSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSegment->flags), minsize,
782 pModule->self, FALSE, FALSE, FALSE );
783 if (!hNewSeg) return 0;
784 pSegment->hSeg = hNewSeg;
785 pSegment->flags |= NE_SEGFLAGS_ALLOCATED;
787 /* a HINSTANCE is the selector of the DSEG */
788 return (HINSTANCE16)SEL(hNewSeg);
792 /***********************************************************************
793 * NE_AllocateSegment (WPROCS.26)
795 * MyAlloc() function for self-loading apps.
797 DWORD WINAPI NE_AllocateSegment( WORD wFlags, WORD wSize, WORD wElem )
799 WORD size = wSize << wElem;
800 HANDLE16 hMem = 0;
802 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
803 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
805 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
806 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
808 WORD hSel = SEL(hMem);
809 WORD access = SelectorAccessRights16(hSel,0,0);
811 access |= 2<<2; /* SEGMENT_CODE */
812 SelectorAccessRights16(hSel,1,access);
814 if (size)
815 return MAKELONG( hMem, SEL(hMem) );
816 else
817 return MAKELONG( 0, hMem );
821 /***********************************************************************
822 * NE_CreateSegments
824 BOOL NE_CreateSegments( NE_MODULE *pModule )
826 SEGTABLEENTRY *pSegment;
827 int i, minsize, seg_count;
829 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
831 pSegment = NE_SEG_TABLE( pModule );
833 if (pModule->flags & NE_FFLAGS_SELFLOAD)
834 seg_count = 1;
835 else
836 seg_count = pModule->seg_count;
837 for (i = 1; i <= seg_count; i++, pSegment++)
839 minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
840 if (i == pModule->ss) minsize += pModule->stack_size;
841 /* The DGROUP is allocated by NE_CreateInstance */
842 if (i == pModule->dgroup) continue;
843 pSegment->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSegment->flags),
844 minsize, pModule->self,
845 !(pSegment->flags & NE_SEGFLAGS_DATA),
846 (pSegment->flags & NE_SEGFLAGS_32BIT) != 0,
847 FALSE /*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
848 if (!pSegment->hSeg) return FALSE;
849 pSegment->flags |= NE_SEGFLAGS_ALLOCATED;
852 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
853 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
854 return TRUE;
858 /**********************************************************************
859 * IsSharedSelector (KERNEL.345)
861 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
863 /* Check whether the selector belongs to a DLL */
864 NE_MODULE *pModule = NE_GetPtr( selector );
865 if (!pModule) return FALSE;
866 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;