Got rid of THREAD_InitDone.
[wine/multimedia.git] / loader / ne / segment.c
blob6ff87d9da602a887715bac1c1c44f5e5482590bd
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"
31 DECLARE_DEBUG_CHANNEL(dll)
32 DECLARE_DEBUG_CHANNEL(fixup)
33 DECLARE_DEBUG_CHANNEL(module)
34 DECLARE_DEBUG_CHANNEL(segment)
36 #define SEL(x) GlobalHandleToSel16(x)
38 /***********************************************************************
39 * NE_GetRelocAddrName
41 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
43 switch(addr_type & 0x7f)
45 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
46 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
47 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
48 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
49 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
50 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
52 return "???";
56 /***********************************************************************
57 * NE_LoadSegment
59 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
61 SEGTABLEENTRY *pSegTable, *pSeg;
62 WORD *pModuleTable;
63 WORD count, i, offset, next_offset;
64 HMODULE16 module;
65 FARPROC16 address = 0;
66 HFILE hf;
67 DWORD res;
68 struct relocation_entry_s *rep, *reloc_entries;
69 BYTE *func_name;
70 int size;
71 char* mem;
73 char buffer[256];
74 int ordinal, additive;
75 unsigned short *sp;
77 pSegTable = NE_SEG_TABLE( pModule );
78 pSeg = pSegTable + segnum - 1;
80 if (pSeg->flags & NE_SEGFLAGS_LOADED) /* already loaded ? */
81 return TRUE;
83 if (!pSeg->filepos) return TRUE; /* No file image, just return */
85 pModuleTable = NE_MODULE_TABLE( pModule );
87 hf = NE_OpenFile( pModule );
88 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
89 segnum, pSeg->hSeg, pSeg->flags );
90 SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
91 if (pSeg->size) size = pSeg->size;
92 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
93 mem = GlobalLock16(pSeg->hSeg);
94 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
96 /* Implement self-loading segments */
97 SELFLOADHEADER *selfloadheader;
98 STACK16FRAME *stack16Top;
99 DWORD oldstack;
100 WORD old_hSeg, new_hSeg;
101 THDB *thdb = THREAD_Current();
102 HFILE hFile32;
103 HFILE16 hFile16;
105 selfloadheader = (SELFLOADHEADER *)
106 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg),0);
107 oldstack = thdb->cur_stack;
108 old_hSeg = pSeg->hSeg;
109 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
110 0xff00 - sizeof(*stack16Top));
111 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
112 stack16Top->frame32 = 0;
113 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
114 stack16Top->entry_point = 0;
115 stack16Top->entry_ip = 0;
116 stack16Top->entry_cs = 0;
117 stack16Top->bp = 0;
118 stack16Top->ip = 0;
119 stack16Top->cs = 0;
120 TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
121 pModule->self,hf,segnum );
122 DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
123 0, FALSE, DUPLICATE_SAME_ACCESS );
124 hFile16 = FILE_AllocDosHandle( hFile32 );
125 new_hSeg = Callbacks->CallLoadAppSegProc(selfloadheader->LoadAppSeg,
126 pModule->self, hFile16,
127 segnum );
128 TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n",new_hSeg);
129 _lclose16( hFile16 );
130 if (SEL(new_hSeg) != SEL(old_hSeg)) {
131 /* Self loaders like creating their own selectors;
132 * they love asking for trouble to Wine developers
134 if (segnum == pModule->dgroup) {
135 memcpy(PTR_SEG_OFF_TO_LIN(SEL(old_hSeg),0),
136 PTR_SEG_OFF_TO_LIN(SEL(new_hSeg),0),
137 pSeg->minsize ? pSeg->minsize : 0x10000);
138 FreeSelector16(SEL(new_hSeg));
139 pSeg->hSeg = old_hSeg;
140 TRACE_(module)("New hSeg allocated for dgroup segment:Old=%d,New=%d\n",
141 old_hSeg, new_hSeg);
142 } else {
143 FreeSelector16(SEL(pSeg->hSeg));
144 pSeg->hSeg = new_hSeg;
148 thdb->cur_stack = oldstack;
150 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
151 ReadFile(hf, mem, size, &res, NULL);
152 else {
154 The following bit of code for "iterated segments" was written without
155 any documentation on the format of these segments. It seems to work,
156 but may be missing something. If you have any doc please either send
157 it to me or fix the code yourself. gfm@werple.mira.net.au
159 char* buff = xmalloc(size);
160 char* curr = buff;
161 ReadFile(hf, buff, size, &res, NULL);
162 while(curr < buff + size) {
163 unsigned int rept = *((short*) curr)++;
164 unsigned int len = *((short*) curr)++;
165 for(; rept > 0; rept--) {
166 char* bytes = curr;
167 unsigned int byte;
168 for(byte = 0; byte < len; byte++)
169 *mem++ = *bytes++;
171 curr += len;
173 free(buff);
176 pSeg->flags |= NE_SEGFLAGS_LOADED;
177 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
178 return TRUE; /* No relocation data, we are done */
180 ReadFile(hf, &count, sizeof(count), &res, NULL);
181 if (!count) return TRUE;
183 TRACE_(fixup)("Fixups for %.*s, segment %d, hSeg %04x\n",
184 *((BYTE *)pModule + pModule->name_table),
185 (char *)pModule + pModule->name_table + 1,
186 segnum, pSeg->hSeg );
187 TRACE_(segment)("Fixups for %.*s, segment %d, hSeg %04x\n",
188 *((BYTE *)pModule + pModule->name_table),
189 (char *)pModule + pModule->name_table + 1,
190 segnum, pSeg->hSeg );
192 reloc_entries = (struct relocation_entry_s *)xmalloc(count * sizeof(struct relocation_entry_s));
193 if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
194 (res != count * sizeof(struct relocation_entry_s)))
196 WARN_(fixup)("Unable to read relocation information\n" );
197 return FALSE;
201 * Go through the relocation table one entry at a time.
203 rep = reloc_entries;
204 for (i = 0; i < count; i++, rep++)
207 * Get the target address corresponding to this entry.
210 /* If additive, there is no target chain list. Instead, add source
211 and target */
212 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
213 rep->relocation_type &= 0x3;
215 switch (rep->relocation_type)
217 case NE_RELTYPE_ORDINAL:
218 module = pModuleTable[rep->target1-1];
219 ordinal = rep->target2;
220 address = NE_GetEntryPoint( module, ordinal );
221 if (!address)
223 NE_MODULE *pTarget = NE_GetPtr( module );
224 if (!pTarget)
225 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
226 module, rep->target1,
227 *((BYTE *)pModule + pModule->name_table),
228 *((BYTE *)pModule + pModule->name_table),
229 (char *)pModule + pModule->name_table + 1 );
230 else
232 ERR_(fixup)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
233 *((BYTE *)pTarget + pTarget->name_table),
234 (char *)pTarget + pTarget->name_table + 1,
235 ordinal );
236 address = (FARPROC16)0xdeadbeef;
239 if (TRACE_ON(fixup))
241 NE_MODULE *pTarget = NE_GetPtr( module );
242 TRACE_(fixup)("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
243 *((BYTE *)pTarget + pTarget->name_table),
244 (char *)pTarget + pTarget->name_table + 1,
245 ordinal, HIWORD(address), LOWORD(address),
246 NE_GetRelocAddrName( rep->address_type, additive ) );
248 break;
250 case NE_RELTYPE_NAME:
251 module = pModuleTable[rep->target1-1];
252 func_name = (char *)pModule + pModule->import_table + rep->target2;
253 memcpy( buffer, func_name+1, *func_name );
254 buffer[*func_name] = '\0';
255 func_name = buffer;
256 ordinal = NE_GetOrdinal( module, func_name );
257 address = NE_GetEntryPoint( module, ordinal );
259 if (ERR_ON(fixup) && !address)
261 NE_MODULE *pTarget = NE_GetPtr( module );
262 ERR_(fixup)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
263 *((BYTE *)pTarget + pTarget->name_table),
264 (char *)pTarget + pTarget->name_table + 1, func_name );
266 if (!address) address = (FARPROC16) 0xdeadbeef;
267 if (TRACE_ON(fixup))
269 NE_MODULE *pTarget = NE_GetPtr( module );
270 TRACE_(fixup)("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
271 *((BYTE *)pTarget + pTarget->name_table),
272 (char *)pTarget + pTarget->name_table + 1,
273 func_name, HIWORD(address), LOWORD(address),
274 NE_GetRelocAddrName( rep->address_type, additive ) );
276 break;
278 case NE_RELTYPE_INTERNAL:
279 if ((rep->target1 & 0xff) == 0xff)
281 address = NE_GetEntryPoint( pModule->self, rep->target2 );
283 else
285 address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
288 TRACE_(fixup)("%d: %04x:%04x %s\n",
289 i + 1, HIWORD(address), LOWORD(address),
290 NE_GetRelocAddrName( rep->address_type, additive ) );
291 break;
293 case NE_RELTYPE_OSFIXUP:
294 /* Relocation type 7:
296 * These appear to be used as fixups for the Windows
297 * floating point emulator. Let's just ignore them and
298 * try to use the hardware floating point. Linux should
299 * successfully emulate the coprocessor if it doesn't
300 * exist.
302 TRACE_(fixup)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
303 i + 1, rep->relocation_type, rep->offset,
304 rep->target1, rep->target2,
305 NE_GetRelocAddrName( rep->address_type, additive ) );
306 continue;
309 offset = rep->offset;
311 /* Apparently, high bit of address_type is sometimes set; */
312 /* we ignore it for now */
313 if (rep->address_type > NE_RADDR_OFFSET32)
315 char module[10];
316 GetModuleName16( pModule->self, module, sizeof(module) );
317 ERR_(fixup)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
318 module, rep->address_type );
321 if (additive)
323 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
324 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
325 switch (rep->address_type & 0x7f)
327 case NE_RADDR_LOWBYTE:
328 *(BYTE *)sp += LOBYTE((int)address);
329 break;
330 case NE_RADDR_OFFSET16:
331 *sp += LOWORD(address);
332 break;
333 case NE_RADDR_POINTER32:
334 *sp += LOWORD(address);
335 *(sp+1) = HIWORD(address);
336 break;
337 case NE_RADDR_SELECTOR:
338 /* Borland creates additive records with offset zero. Strange, but OK */
339 if (*sp)
340 ERR_(fixup)("Additive selector to %04x.Please report\n",*sp);
341 else
342 *sp = HIWORD(address);
343 break;
344 default:
345 goto unknown;
348 else /* non-additive fixup */
352 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
353 next_offset = *sp;
354 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
355 switch (rep->address_type & 0x7f)
357 case NE_RADDR_LOWBYTE:
358 *(BYTE *)sp = LOBYTE((int)address);
359 break;
360 case NE_RADDR_OFFSET16:
361 *sp = LOWORD(address);
362 break;
363 case NE_RADDR_POINTER32:
364 *(FARPROC16 *)sp = address;
365 break;
366 case NE_RADDR_SELECTOR:
367 *sp = SELECTOROF(address);
368 break;
369 default:
370 goto unknown;
372 if (next_offset == offset) break; /* avoid infinite loop */
373 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
374 offset = next_offset;
375 } while (offset != 0xffff);
379 free(reloc_entries);
380 return TRUE;
382 unknown:
383 WARN_(fixup)("WARNING: %d: unknown ADDR TYPE %d, "
384 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
385 i + 1, rep->address_type, rep->relocation_type,
386 rep->offset, rep->target1, rep->target2);
387 free(reloc_entries);
388 return FALSE;
392 /***********************************************************************
393 * NE_LoadAllSegments
395 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
397 int i;
398 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
400 if (pModule->flags & NE_FFLAGS_SELFLOAD)
402 HFILE hf;
403 HFILE16 hFile16;
404 /* Handle self-loading modules */
405 SELFLOADHEADER *selfloadheader;
406 STACK16FRAME *stack16Top;
407 THDB *thdb = THREAD_Current();
408 HMODULE16 hselfload = GetModuleHandle16("WPROCS");
409 DWORD oldstack;
410 WORD saved_hSeg = pSegTable[pModule->dgroup - 1].hSeg;
412 TRACE_(module)("%.*s is a self-loading module!\n",
413 *((BYTE*)pModule + pModule->name_table),
414 (char *)pModule + pModule->name_table + 1);
415 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
416 selfloadheader = (SELFLOADHEADER *)
417 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg), 0);
418 selfloadheader->EntryAddrProc = NE_GetEntryPoint(hselfload,27);
419 selfloadheader->MyAlloc = NE_GetEntryPoint(hselfload,28);
420 selfloadheader->SetOwner = NE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
421 pModule->self_loading_sel = SEL(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
422 oldstack = thdb->cur_stack;
423 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
424 0xff00 - sizeof(*stack16Top) );
425 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
426 stack16Top->frame32 = 0;
427 stack16Top->ebp = 0;
428 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
429 stack16Top->entry_point = 0;
430 stack16Top->entry_ip = 0;
431 stack16Top->entry_cs = 0;
432 stack16Top->bp = 0;
433 stack16Top->ip = 0;
434 stack16Top->cs = 0;
436 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule),
437 GetCurrentProcess(), &hf, 0, FALSE, DUPLICATE_SAME_ACCESS );
438 hFile16 = FILE_AllocDosHandle( hf );
439 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
440 pModule->self,hFile16);
441 Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self,hFile16);
442 TRACE_(dll)("Return from CallBootAppProc\n");
443 _lclose16(hf);
444 /* some BootApp procs overwrite the segment handle of dgroup */
445 pSegTable[pModule->dgroup - 1].hSeg = saved_hSeg;
446 thdb->cur_stack = oldstack;
448 for (i = 2; i <= pModule->seg_count; i++)
449 if (!NE_LoadSegment( pModule, i )) return FALSE;
451 else
453 for (i = 1; i <= pModule->seg_count; i++)
454 if (!NE_LoadSegment( pModule, i )) return FALSE;
456 return TRUE;
460 /***********************************************************************
461 * NE_FixupSegmentPrologs
463 * Fixup exported functions prologs of one segment
465 void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
467 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
468 ET_BUNDLE *bundle;
469 ET_ENTRY *entry;
470 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
471 BYTE *pSeg, *pFunc;
473 TRACE_(module)("(%d);\n", segnum);
475 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
477 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
478 return;
480 if (!(dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg)))
481 return;
483 pSeg = PTR_SEG_OFF_TO_LIN(sel, 0);
485 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);
487 do {
488 TRACE_(module)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
489 if (!(num_entries = bundle->last - bundle->first))
490 return;
491 entry = (ET_ENTRY *)((BYTE *)bundle+6);
492 while (num_entries--)
494 /*TRACE(module, "entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
495 if (entry->segnum == segnum)
497 pFunc = ((BYTE *)pSeg+entry->offs);
498 TRACE_(module)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
499 if (*(pFunc+2) == 0x90)
501 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
503 TRACE_(module)("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
504 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
507 if (*(WORD *)pFunc == 0xd88c)
509 if ((entry->flags & 2)) /* public data ? */
511 TRACE_(module)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
512 *pFunc = 0xb8; /* mov ax, */
513 *(WORD *)(pFunc+1) = dgroup;
515 else
516 if ((pModule->flags & NE_FFLAGS_MULTIPLEDATA)
517 && (entry->flags & 1)) /* exported ? */
519 TRACE_(module)("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
520 *(WORD *)pFunc = 0x9090; /* nop, nop */
525 entry++;
527 } while ( (bundle->next)
528 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
532 /***********************************************************************
533 * PatchCodeHandle
535 * Needed for self-loading modules.
537 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
539 WORD segnum;
540 WORD sel = SEL(hSeg);
541 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
542 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
544 TRACE_(module)("(%04x);\n", hSeg);
546 /* find the segment number of the module that belongs to hSeg */
547 for (segnum = 1; segnum <= pModule->seg_count; segnum++)
549 if (SEL(pSegTable[segnum-1].hSeg) == sel)
551 NE_FixupSegmentPrologs(pModule, segnum);
552 break;
556 return MAKELONG(hSeg, sel);
559 /***********************************************************************
560 * NE_FixupPrologs
562 * Fixup the exported functions prologs.
564 void NE_FixupPrologs( NE_MODULE *pModule )
566 WORD segnum;
568 TRACE_(module)("(%04x)\n", pModule->self );
570 if (pModule->flags & NE_FFLAGS_SELFLOAD)
571 NE_FixupSegmentPrologs(pModule, 1);
572 else
573 for (segnum=1; segnum <= pModule->seg_count; segnum++)
574 NE_FixupSegmentPrologs(pModule, segnum);
577 /***********************************************************************
578 * NE_GetDLLInitParams
580 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
581 WORD *hInst, WORD *ds, WORD *heap )
583 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
585 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
587 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
589 /* Not SINGLEDATA */
590 ERR_(dll)("Library is not marked SINGLEDATA\n");
591 exit(1);
593 else /* DATA NONE DLL */
595 *ds = 0;
596 *heap = 0;
599 else /* DATA SINGLE DLL */
601 if (pModule->dgroup) {
602 *ds = SEL(pSegTable[pModule->dgroup-1].hSeg);
603 *heap = pModule->heap_size;
605 else /* hmm, DLL has no dgroup,
606 but why has it NE_FFLAGS_SINGLEDATA set ?
607 Buggy DLL compiler ? */
609 *ds = 0;
610 *heap = 0;
614 *hInst = *ds ? *ds : pModule->self;
618 /***********************************************************************
619 * NE_InitDLL
621 * Call the DLL initialization code
623 static BOOL NE_InitDLL( TDB* pTask, NE_MODULE *pModule )
625 SEGTABLEENTRY *pSegTable;
626 WORD hInst, ds, heap;
627 CONTEXT context;
629 pSegTable = NE_SEG_TABLE( pModule );
631 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
632 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
634 /* Call USER signal handler for Win3.1 compatibility. */
635 if (pTask && pTask->userhandler)
636 pTask->userhandler( pModule->self, USIG16_DLL_LOAD, 0,
637 pTask->hInstance, pTask->hQueue );
639 if (!pModule->cs) return TRUE; /* no initialization code */
642 /* Registers at initialization must be:
643 * cx heap size
644 * di library instance
645 * ds data segment if any
646 * es:si command line (always 0)
649 memset( &context, 0, sizeof(context) );
651 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
653 ECX_reg(&context) = heap;
654 EDI_reg(&context) = hInst;
655 DS_reg(&context) = ds;
656 ES_reg(&context) = ds; /* who knows ... */
658 CS_reg(&context) = SEL(pSegTable[pModule->cs-1].hSeg);
659 EIP_reg(&context) = pModule->ip;
660 EBP_reg(&context) = OFFSETOF(THREAD_Current()->cur_stack)
661 + (WORD)&((STACK16FRAME*)0)->bp;
664 pModule->cs = 0; /* Don't initialize it twice */
665 TRACE_(dll)("Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
666 CS_reg(&context), IP_reg(&context), DS_reg(&context),
667 DI_reg(&context), CX_reg(&context) );
668 Callbacks->CallRegisterShortProc( &context, 0 );
669 return TRUE;
672 /***********************************************************************
673 * NE_CallDllEntryPoint
675 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
678 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
680 WORD hInst, ds, heap;
681 FARPROC16 entryPoint;
682 WORD ordinal;
683 CONTEXT context;
684 THDB *thdb = THREAD_Current();
685 LPBYTE stack = (LPBYTE)THREAD_STACK16(thdb);
687 if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
688 if (!(ordinal = NE_GetOrdinal( pModule->self, "DllEntryPoint" ))) return;
689 if (!(entryPoint = NE_GetEntryPoint( pModule->self, ordinal ))) return;
691 memset( &context, 0, sizeof(context) );
693 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
695 DS_reg(&context) = ds;
696 ES_reg(&context) = ds; /* who knows ... */
698 CS_reg(&context) = HIWORD(entryPoint);
699 IP_reg(&context) = LOWORD(entryPoint);
700 EBP_reg(&context) = OFFSETOF( thdb->cur_stack )
701 + (WORD)&((STACK16FRAME*)0)->bp;
703 *(DWORD *)(stack - 4) = dwReason; /* dwReason */
704 *(WORD *) (stack - 6) = hInst; /* hInst */
705 *(WORD *) (stack - 8) = ds; /* wDS */
706 *(WORD *) (stack - 10) = heap; /* wHeapSize */
707 *(DWORD *)(stack - 14) = 0; /* dwReserved1 */
708 *(WORD *) (stack - 16) = 0; /* wReserved2 */
710 TRACE_(dll)("Calling DllEntryPoint, cs:ip=%04lx:%04x\n",
711 CS_reg(&context), IP_reg(&context));
713 Callbacks->CallRegisterShortProc( &context, 16 );
717 /***********************************************************************
718 * NE_InitializeDLLs
720 * Recursively initialize all DLLs (according to the order in which
721 * they where loaded).
723 void NE_InitializeDLLs( HMODULE16 hModule )
725 TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
726 NE_MODULE *pModule;
727 HMODULE16 *pDLL;
729 if (!(pModule = NE_GetPtr( hModule ))) return;
730 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
732 if (pModule->dlls_to_init)
734 HGLOBAL16 to_init = pModule->dlls_to_init;
735 pModule->dlls_to_init = 0;
736 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
738 NE_InitializeDLLs( *pDLL );
740 GlobalFree16( to_init );
742 NE_InitDLL( pTask, pModule );
743 NE_CallDllEntryPoint( pModule, DLL_PROCESS_ATTACH );
747 /***********************************************************************
748 * NE_CreateInstance
750 * If lib_only is TRUE, handle the module like a library even if it is a .EXE
752 HINSTANCE16 NE_CreateInstance( NE_MODULE *pModule, HINSTANCE16 *prev,
753 BOOL lib_only )
755 SEGTABLEENTRY *pSegment;
756 int minsize;
757 HINSTANCE16 hNewInstance;
759 if (pModule->dgroup == 0)
761 if (prev) *prev = pModule->self;
762 return pModule->self;
765 pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
766 if (prev) *prev = SEL(pSegment->hSeg);
768 /* if it's a library, create a new instance only the first time */
769 if (pSegment->hSeg)
771 if (pModule->flags & NE_FFLAGS_LIBMODULE) return SEL(pSegment->hSeg);
772 if (lib_only) return SEL(pSegment->hSeg);
775 minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
776 if (pModule->ss == pModule->dgroup) minsize += pModule->stack_size;
777 minsize += pModule->heap_size;
778 hNewInstance = GLOBAL_Alloc( GMEM_ZEROINIT | GMEM_FIXED, minsize,
779 pModule->self, FALSE, FALSE, FALSE );
780 if (!hNewInstance) return 0;
781 pSegment->hSeg = hNewInstance;
782 pSegment->flags |= NE_SEGFLAGS_ALLOCATED;
783 return hNewInstance;
787 /***********************************************************************
788 * NE_Ne2MemFlags
790 * This function translates NE segment flags to GlobalAlloc flags
792 static WORD NE_Ne2MemFlags(WORD flags)
794 WORD memflags = 0;
795 #if 1
796 if (flags & NE_SEGFLAGS_DISCARDABLE)
797 memflags |= GMEM_DISCARDABLE;
798 if (flags & NE_SEGFLAGS_MOVEABLE ||
799 ( ! (flags & NE_SEGFLAGS_DATA) &&
800 ! (flags & NE_SEGFLAGS_LOADED) &&
801 ! (flags & NE_SEGFLAGS_ALLOCATED)
804 memflags |= GMEM_MOVEABLE;
805 memflags |= GMEM_ZEROINIT;
806 #else
807 memflags = GMEM_ZEROINIT | GMEM_FIXED;
808 #endif
809 return memflags;
812 /***********************************************************************
813 * NE_AllocateSegment (WPROCS.26)
815 * MyAlloc() function for self-loading apps.
817 DWORD WINAPI NE_AllocateSegment( WORD wFlags, WORD wSize, WORD wElem )
819 WORD size = wSize << wElem;
820 HANDLE16 hMem = 0;
822 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
823 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
825 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
826 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
828 WORD hSel = SEL(hMem);
829 WORD access = SelectorAccessRights16(hSel,0,0);
831 access |= 2<<2; /* SEGMENT_CODE */
832 SelectorAccessRights16(hSel,1,access);
834 if (size)
835 return MAKELONG( hMem, SEL(hMem) );
836 else
837 return MAKELONG( 0, hMem );
841 /***********************************************************************
842 * NE_CreateSegments
844 BOOL NE_CreateSegments( NE_MODULE *pModule )
846 SEGTABLEENTRY *pSegment;
847 int i, minsize, seg_count;
849 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
851 pSegment = NE_SEG_TABLE( pModule );
853 if (pModule->flags & NE_FFLAGS_SELFLOAD)
854 seg_count = 1;
855 else
856 seg_count = pModule->seg_count;
857 for (i = 1; i <= seg_count; i++, pSegment++)
859 minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
860 if (i == pModule->ss) minsize += pModule->stack_size;
861 /* The DGROUP is allocated by NE_CreateInstance */
862 if (i == pModule->dgroup) continue;
863 pSegment->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSegment->flags),
864 minsize, pModule->self,
865 !(pSegment->flags & NE_SEGFLAGS_DATA),
866 FALSE,
867 FALSE /*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
868 if (!pSegment->hSeg) return FALSE;
869 pSegment->flags |= NE_SEGFLAGS_ALLOCATED;
872 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
873 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
874 return TRUE;
878 /**********************************************************************
879 * IsSharedSelector (KERNEL.345)
881 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
883 /* Check whether the selector belongs to a DLL */
884 NE_MODULE *pModule = NE_GetPtr( selector );
885 if (!pModule) return FALSE;
886 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;