Release 981025.
[wine/multimedia.git] / loader / ne / segment.c
blobc8186f015fc46b31b52fc23d74ffafaeadd6a520
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>
18 #include "neexe.h"
19 #include "windows.h"
20 #include "global.h"
21 #include "task.h"
22 #include "selectors.h"
23 #include "callback.h"
24 #include "file.h"
25 #include "module.h"
26 #include "stackframe.h"
27 #include "debug.h"
28 #include "xmalloc.h"
30 #define SEL(x) GlobalHandleToSel(x)
32 /***********************************************************************
33 * NE_GetRelocAddrName
35 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
37 switch(addr_type & 0x7f)
39 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
40 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
41 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
42 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
43 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
44 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
46 return "???";
50 /***********************************************************************
51 * NE_LoadSegment
53 BOOL32 NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
55 SEGTABLEENTRY *pSegTable, *pSeg;
56 WORD *pModuleTable;
57 WORD count, i, offset, next_offset;
58 HMODULE16 module;
59 FARPROC16 address = 0;
60 int fd;
61 struct relocation_entry_s *rep, *reloc_entries;
62 BYTE *func_name;
63 int size;
64 char* mem;
66 char buffer[256];
67 int ordinal, additive;
68 unsigned short *sp;
70 pSegTable = NE_SEG_TABLE( pModule );
71 pSeg = pSegTable + segnum - 1;
73 if (pSeg->flags & NE_SEGFLAGS_LOADED) /* already loaded ? */
74 return TRUE;
76 if (!pSeg->filepos) return TRUE; /* No file image, just return */
78 pModuleTable = NE_MODULE_TABLE( pModule );
80 fd = NE_OpenFile( pModule );
81 TRACE(module, "Loading segment %d, hSeg=%04x, flags=%04x\n",
82 segnum, pSeg->hSeg, pSeg->flags );
83 lseek( fd, pSeg->filepos << pModule->alignment, SEEK_SET );
84 if (pSeg->size) size = pSeg->size;
85 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
86 mem = GlobalLock16(pSeg->hSeg);
87 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
89 /* Implement self loading segments */
90 SELFLOADHEADER *selfloadheader;
91 STACK16FRAME *stack16Top;
92 DWORD oldstack;
93 WORD old_hSeg, new_hSeg;
94 THDB *thdb = THREAD_Current();
95 HFILE32 hf = FILE_DupUnixHandle( fd );
97 selfloadheader = (SELFLOADHEADER *)
98 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg),0);
99 oldstack = thdb->cur_stack;
100 old_hSeg = pSeg->hSeg;
101 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
102 0xff00 - sizeof(*stack16Top));
103 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
104 stack16Top->frame32 = 0;
105 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
106 stack16Top->entry_point = 0;
107 stack16Top->entry_ip = 0;
108 stack16Top->entry_cs = 0;
109 stack16Top->bp = 0;
110 stack16Top->ip = 0;
111 stack16Top->cs = 0;
112 TRACE(dll,"CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
113 pModule->self,hf,segnum );
114 new_hSeg = Callbacks->CallLoadAppSegProc(selfloadheader->LoadAppSeg,
115 pModule->self,
116 HFILE32_TO_HFILE16(hf),
117 segnum );
118 TRACE(dll,"Ret CallLoadAppSegProc: hSeg = 0x%04x\n",new_hSeg);
119 _lclose32( hf );
120 if (SEL(new_hSeg) != SEL(old_hSeg)) {
121 /* Self loaders like creating their own selectors;
122 * they love asking for trouble to Wine developers
124 if (segnum == pModule->dgroup) {
125 memcpy(PTR_SEG_OFF_TO_LIN(SEL(old_hSeg),0),
126 PTR_SEG_OFF_TO_LIN(SEL(new_hSeg),0),
127 pSeg->minsize ? pSeg->minsize : 0x10000);
128 FreeSelector(SEL(new_hSeg));
129 pSeg->hSeg = old_hSeg;
130 TRACE(module, "New hSeg allocated for dgroup segment:Old=%d,New=%d\n",
131 old_hSeg, new_hSeg);
132 } else {
133 FreeSelector(SEL(pSeg->hSeg));
134 pSeg->hSeg = new_hSeg;
138 thdb->cur_stack = oldstack;
140 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
141 read(fd, mem, size);
142 else {
144 The following bit of code for "iterated segments" was written without
145 any documentation on the format of these segments. It seems to work,
146 but may be missing something. If you have any doc please either send
147 it to me or fix the code yourself. gfm@werple.mira.net.au
149 char* buff = xmalloc(size);
150 char* curr = buff;
151 read(fd, buff, size);
152 while(curr < buff + size) {
153 unsigned int rept = *((short*) curr)++;
154 unsigned int len = *((short*) curr)++;
155 for(; rept > 0; rept--) {
156 char* bytes = curr;
157 unsigned int byte;
158 for(byte = 0; byte < len; byte++)
159 *mem++ = *bytes++;
161 curr += len;
163 free(buff);
166 pSeg->flags |= NE_SEGFLAGS_LOADED;
167 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
168 return TRUE; /* No relocation data, we are done */
170 read( fd, &count, sizeof(count) );
171 if (!count) return TRUE;
173 TRACE(fixup, "Fixups for %.*s, segment %d, hSeg %04x\n",
174 *((BYTE *)pModule + pModule->name_table),
175 (char *)pModule + pModule->name_table + 1,
176 segnum, pSeg->hSeg );
177 TRACE(segment, "Fixups for %.*s, segment %d, hSeg %04x\n",
178 *((BYTE *)pModule + pModule->name_table),
179 (char *)pModule + pModule->name_table + 1,
180 segnum, pSeg->hSeg );
182 reloc_entries = (struct relocation_entry_s *)xmalloc(count * sizeof(struct relocation_entry_s));
183 if (read( fd, reloc_entries, count * sizeof(struct relocation_entry_s)) !=
184 count * sizeof(struct relocation_entry_s))
186 WARN(fixup, "Unable to read relocation information\n" );
187 return FALSE;
191 * Go through the relocation table one entry at a time.
193 rep = reloc_entries;
194 for (i = 0; i < count; i++, rep++)
197 * Get the target address corresponding to this entry.
200 /* If additive, there is no target chain list. Instead, add source
201 and target */
202 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
203 rep->relocation_type &= 0x3;
205 switch (rep->relocation_type)
207 case NE_RELTYPE_ORDINAL:
208 module = pModuleTable[rep->target1-1];
209 ordinal = rep->target2;
210 address = NE_GetEntryPoint( module, ordinal );
211 if (!address)
213 NE_MODULE *pTarget = NE_GetPtr( module );
214 if (!pTarget)
215 WARN(module, "Module not found: %04x, reference %d of module %*.*s\n",
216 module, rep->target1,
217 *((BYTE *)pModule + pModule->name_table),
218 *((BYTE *)pModule + pModule->name_table),
219 (char *)pModule + pModule->name_table + 1 );
220 else
222 ERR(fixup, "No handler for %.*s.%d, setting to 0xdeadbeef\n",
223 *((BYTE *)pTarget + pTarget->name_table),
224 (char *)pTarget + pTarget->name_table + 1,
225 ordinal );
226 address = (FARPROC16)0xdeadbeef;
229 if (TRACE_ON(fixup))
231 NE_MODULE *pTarget = NE_GetPtr( module );
232 TRACE( fixup, "%d: %.*s.%d=%04x:%04x %s\n", i + 1,
233 *((BYTE *)pTarget + pTarget->name_table),
234 (char *)pTarget + pTarget->name_table + 1,
235 ordinal, HIWORD(address), LOWORD(address),
236 NE_GetRelocAddrName( rep->address_type, additive ) );
238 break;
240 case NE_RELTYPE_NAME:
241 module = pModuleTable[rep->target1-1];
242 func_name = (char *)pModule + pModule->import_table + rep->target2;
243 memcpy( buffer, func_name+1, *func_name );
244 buffer[*func_name] = '\0';
245 func_name = buffer;
246 ordinal = NE_GetOrdinal( module, func_name );
247 address = NE_GetEntryPoint( module, ordinal );
249 if (ERR_ON(fixup) && !address)
251 NE_MODULE *pTarget = NE_GetPtr( module );
252 ERR(fixup, "Warning: no handler for %.*s.%s, setting to 0xdeadbeef\n",
253 *((BYTE *)pTarget + pTarget->name_table),
254 (char *)pTarget + pTarget->name_table + 1, func_name );
256 if (!address) address = (FARPROC16) 0xdeadbeef;
257 if (TRACE_ON(fixup))
259 NE_MODULE *pTarget = NE_GetPtr( module );
260 TRACE( fixup, "%d: %.*s.%s=%04x:%04x %s\n", i + 1,
261 *((BYTE *)pTarget + pTarget->name_table),
262 (char *)pTarget + pTarget->name_table + 1,
263 func_name, HIWORD(address), LOWORD(address),
264 NE_GetRelocAddrName( rep->address_type, additive ) );
266 break;
268 case NE_RELTYPE_INTERNAL:
269 if ((rep->target1 & 0xff) == 0xff)
271 address = NE_GetEntryPoint( pModule->self, rep->target2 );
273 else
275 address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
278 TRACE( fixup,"%d: %04x:%04x %s\n",
279 i + 1, HIWORD(address), LOWORD(address),
280 NE_GetRelocAddrName( rep->address_type, additive ) );
281 break;
283 case NE_RELTYPE_OSFIXUP:
284 /* Relocation type 7:
286 * These appear to be used as fixups for the Windows
287 * floating point emulator. Let's just ignore them and
288 * try to use the hardware floating point. Linux should
289 * successfully emulate the coprocessor if it doesn't
290 * exist.
292 TRACE( fixup, "%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
293 i + 1, rep->relocation_type, rep->offset,
294 rep->target1, rep->target2,
295 NE_GetRelocAddrName( rep->address_type, additive ) );
296 continue;
299 offset = rep->offset;
301 /* Apparently, high bit of address_type is sometimes set; */
302 /* we ignore it for now */
303 if (rep->address_type > NE_RADDR_OFFSET32)
305 char module[10];
306 GetModuleName( pModule->self, module, sizeof(module) );
307 ERR( fixup, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
308 module, rep->address_type );
311 if (additive)
313 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
314 TRACE( fixup," %04x:%04x\n", offset, *sp );
315 switch (rep->address_type & 0x7f)
317 case NE_RADDR_LOWBYTE:
318 *(BYTE *)sp += LOBYTE((int)address);
319 break;
320 case NE_RADDR_OFFSET16:
321 *sp += LOWORD(address);
322 break;
323 case NE_RADDR_POINTER32:
324 *sp += LOWORD(address);
325 *(sp+1) = HIWORD(address);
326 break;
327 case NE_RADDR_SELECTOR:
328 /* Borland creates additive records with offset zero. Strange, but OK */
329 if (*sp)
330 ERR(fixup,"Additive selector to %04x.Please report\n",*sp);
331 else
332 *sp = HIWORD(address);
333 break;
334 default:
335 goto unknown;
338 else /* non-additive fixup */
342 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
343 next_offset = *sp;
344 TRACE( fixup," %04x:%04x\n", offset, *sp );
345 switch (rep->address_type & 0x7f)
347 case NE_RADDR_LOWBYTE:
348 *(BYTE *)sp = LOBYTE((int)address);
349 break;
350 case NE_RADDR_OFFSET16:
351 *sp = LOWORD(address);
352 break;
353 case NE_RADDR_POINTER32:
354 *(FARPROC16 *)sp = address;
355 break;
356 case NE_RADDR_SELECTOR:
357 *sp = SELECTOROF(address);
358 break;
359 default:
360 goto unknown;
362 if (next_offset == offset) break; /* avoid infinite loop */
363 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
364 offset = next_offset;
365 } while (offset != 0xffff);
369 free(reloc_entries);
370 return TRUE;
372 unknown:
373 WARN(fixup, "WARNING: %d: unknown ADDR TYPE %d, "
374 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
375 i + 1, rep->address_type, rep->relocation_type,
376 rep->offset, rep->target1, rep->target2);
377 free(reloc_entries);
378 return FALSE;
382 /***********************************************************************
383 * NE_LoadAllSegments
385 BOOL32 NE_LoadAllSegments( NE_MODULE *pModule )
387 int i;
388 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
390 if (pModule->flags & NE_FFLAGS_SELFLOAD)
392 HFILE32 hf;
393 /* Handle self loading modules */
394 SELFLOADHEADER *selfloadheader;
395 STACK16FRAME *stack16Top;
396 THDB *thdb = THREAD_Current();
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 = GlobalHandleToSel(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
411 oldstack = thdb->cur_stack;
412 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
413 0xff00 - sizeof(*stack16Top) );
414 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
415 stack16Top->frame32 = 0;
416 stack16Top->ebp = 0;
417 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
418 stack16Top->entry_point = 0;
419 stack16Top->entry_ip = 0;
420 stack16Top->entry_cs = 0;
421 stack16Top->bp = 0;
422 stack16Top->ip = 0;
423 stack16Top->cs = 0;
425 hf = FILE_DupUnixHandle( NE_OpenFile( pModule ) );
426 TRACE(dll,"CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",pModule->self,
427 HFILE32_TO_HFILE16(hf));
428 Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self,
429 HFILE32_TO_HFILE16(hf));
430 TRACE(dll,"Return from CallBootAppProc\n");
431 _lclose32(hf);
432 /* some BootApp procs overwrite the segment handle of dgroup */
433 pSegTable[pModule->dgroup - 1].hSeg = saved_hSeg;
434 thdb->cur_stack = oldstack;
436 for (i = 2; i <= pModule->seg_count; i++)
437 if (!NE_LoadSegment( pModule, i )) return FALSE;
439 else
441 for (i = 1; i <= pModule->seg_count; i++)
442 if (!NE_LoadSegment( pModule, i )) return FALSE;
444 return TRUE;
448 /***********************************************************************
449 * PatchCodeHandle
451 * Needed for self-loading modules.
454 /* It does nothing */
455 DWORD WINAPI PatchCodeHandle(HANDLE16 hSel)
457 FIXME(module,"(%04x): stub.\n",hSel);
458 return (DWORD)NULL;
462 /***********************************************************************
463 * NE_FixupPrologs
465 * Fixup the exported functions prologs.
467 void NE_FixupPrologs( NE_MODULE *pModule )
469 SEGTABLEENTRY *pSegTable;
470 WORD dgroup = 0;
471 WORD sel;
472 BYTE *p, *fixup_ptr, count;
473 dbg_decl_str(module, 512);
475 pSegTable = NE_SEG_TABLE(pModule);
476 if (pModule->flags & NE_FFLAGS_SINGLEDATA)
477 dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg);
479 TRACE(module, "(%04x)\n", pModule->self );
480 p = (BYTE *)pModule + pModule->entry_table;
481 while (*p)
483 if (p[1] == 0) /* Unused entry */
485 p += 2; /* Skip it */
486 continue;
488 if (p[1] == 0xfe) /* Constant entry */
490 p += 2 + *p * 3; /* Skip it */
491 continue;
494 /* Now fixup the entries of this bundle */
495 count = *p;
496 sel = p[1];
497 p += 2;
498 while (count-- > 0)
500 dbg_reset_str(module);
501 dsprintf(module,"Flags: %04x, sel %02x ", *p, sel);
502 /* According to the output generated by TDUMP, the flags mean:
503 * 0x0001 function is exported
504 * 0x0002 Single data (seems to occur only in DLLs)
506 if (sel == 0xff) { /* moveable */
507 dsprintf(module, "(%02x) o %04x", p[3], *(WORD *)(p+4) );
508 fixup_ptr = (char *)GET_SEL_BASE(SEL(pSegTable[p[3]-1].hSeg)) + *(WORD *)(p + 4);
509 } else { /* fixed */
510 dsprintf(module, "offset %04x", *(WORD *)(p+1) );
511 fixup_ptr = (char *)GET_SEL_BASE(SEL(pSegTable[sel-1].hSeg)) +
512 *(WORD *)(p + 1);
514 TRACE(module, "%s Signature: %02x %02x %02x,ff %x\n",
515 dbg_str(module), fixup_ptr[0], fixup_ptr[1],
516 fixup_ptr[2], pModule->flags );
517 if (*p & 0x0001)
519 /* Verify the signature */
520 if (((fixup_ptr[0] == 0x1e && fixup_ptr[1] == 0x58)
521 || (fixup_ptr[0] == 0x8c && fixup_ptr[1] == 0xd8))
522 && fixup_ptr[2] == 0x90)
524 if (*p & 0x0002)
526 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA)
528 /* can this happen? */
529 ERR(fixup, "FixupPrologs got confused\n" );
531 else if (pModule->flags & NE_FFLAGS_SINGLEDATA)
533 *fixup_ptr = 0xb8; /* MOV AX, */
534 *(WORD *)(fixup_ptr+1) = dgroup;
537 else
539 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA) {
540 fixup_ptr[0] = 0x90; /* non-library: NOPs */
541 fixup_ptr[1] = 0x90;
542 fixup_ptr[2] = 0x90;
545 } else {
546 WARN(fixup, "Unknown signature\n" );
549 else
550 TRACE(module,"\n");
551 p += (sel == 0xff) ? 6 : 3;
556 /***********************************************************************
557 * NE_GetDLLInitParams
559 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
560 WORD *hInst, WORD *ds, WORD *heap )
562 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
564 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
566 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
568 /* Not SINGLEDATA */
569 ERR(dll, "Library is not marked SINGLEDATA\n");
570 exit(1);
572 else /* DATA NONE DLL */
574 *ds = 0;
575 *heap = 0;
578 else /* DATA SINGLE DLL */
580 if (pModule->dgroup) {
581 *ds = SEL(pSegTable[pModule->dgroup-1].hSeg);
582 *heap = pModule->heap_size;
584 else /* hmm, DLL has no dgroup,
585 but why has it NE_FFLAGS_SINGLEDATA set ?
586 Buggy DLL compiler ? */
588 *ds = 0;
589 *heap = 0;
593 *hInst = *ds ? *ds : pModule->self;
597 /***********************************************************************
598 * NE_InitDLL
600 * Call the DLL initialization code
602 static BOOL32 NE_InitDLL( TDB* pTask, NE_MODULE *pModule )
604 SEGTABLEENTRY *pSegTable;
605 WORD hInst, ds, heap;
606 CONTEXT context;
608 pSegTable = NE_SEG_TABLE( pModule );
610 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
611 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
613 /* Call USER signal handler. This is necessary to install a
614 * proper loader for HICON and HCURSOR resources that this DLL
615 * may contain. InitApp() does this for task modules. */
617 if (pTask && pTask->userhandler)
619 pTask->userhandler( pModule->self, USIG_DLL_LOAD, 0, pTask->hInstance,
620 pTask->hQueue );
623 if (!pModule->cs) return TRUE; /* no initialization code */
626 /* Registers at initialization must be:
627 * cx heap size
628 * di library instance
629 * ds data segment if any
630 * es:si command line (always 0)
633 memset( &context, 0, sizeof(context) );
635 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
637 ECX_reg(&context) = heap;
638 EDI_reg(&context) = hInst;
639 DS_reg(&context) = ds;
640 ES_reg(&context) = ds; /* who knows ... */
642 CS_reg(&context) = SEL(pSegTable[pModule->cs-1].hSeg);
643 EIP_reg(&context) = pModule->ip;
644 EBP_reg(&context) = OFFSETOF(THREAD_Current()->cur_stack)
645 + (WORD)&((STACK16FRAME*)0)->bp;
648 pModule->cs = 0; /* Don't initialize it twice */
649 TRACE(dll, "Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
650 CS_reg(&context), IP_reg(&context), DS_reg(&context),
651 DI_reg(&context), CX_reg(&context) );
652 Callbacks->CallRegisterShortProc( &context, 0 );
653 return TRUE;
656 /***********************************************************************
657 * NE_CallDllEntryPoint
659 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
662 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
664 WORD hInst, ds, heap;
665 FARPROC16 entryPoint;
666 WORD ordinal;
667 CONTEXT context;
668 THDB *thdb = THREAD_Current();
669 LPBYTE stack = (LPBYTE)THREAD_STACK16(thdb);
671 if (pModule->expected_version < 0x0400) return;
672 if (!(ordinal = NE_GetOrdinal( pModule->self, "DllEntryPoint" ))) return;
673 if (!(entryPoint = NE_GetEntryPoint( pModule->self, ordinal ))) return;
675 memset( &context, 0, sizeof(context) );
677 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
679 DS_reg(&context) = ds;
680 ES_reg(&context) = ds; /* who knows ... */
682 CS_reg(&context) = HIWORD(entryPoint);
683 IP_reg(&context) = LOWORD(entryPoint);
684 EBP_reg(&context) = OFFSETOF( thdb->cur_stack )
685 + (WORD)&((STACK16FRAME*)0)->bp;
687 *(DWORD *)(stack - 4) = dwReason; /* dwReason */
688 *(WORD *) (stack - 6) = hInst; /* hInst */
689 *(WORD *) (stack - 8) = ds; /* wDS */
690 *(WORD *) (stack - 10) = heap; /* wHeapSize */
691 *(DWORD *)(stack - 14) = 0; /* dwReserved1 */
692 *(WORD *) (stack - 16) = 0; /* wReserved2 */
694 TRACE(dll, "Calling DllEntryPoint, cs:ip=%04lx:%04x\n",
695 CS_reg(&context), IP_reg(&context));
697 Callbacks->CallRegisterShortProc( &context, 16 );
701 /***********************************************************************
702 * NE_InitializeDLLs
704 * Recursively initialize all DLLs (according to the order in which
705 * they where loaded).
707 void NE_InitializeDLLs( HMODULE16 hModule )
709 TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
710 NE_MODULE *pModule;
711 HMODULE16 *pDLL;
713 if (!(pModule = NE_GetPtr( hModule ))) return;
714 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
716 if (pModule->dlls_to_init)
718 HGLOBAL16 to_init = pModule->dlls_to_init;
719 pModule->dlls_to_init = 0;
720 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
722 NE_InitializeDLLs( *pDLL );
724 GlobalFree16( to_init );
726 NE_InitDLL( pTask, pModule );
727 NE_CallDllEntryPoint( pModule, DLL_PROCESS_ATTACH );
731 /***********************************************************************
732 * NE_CreateInstance
734 * If lib_only is TRUE, handle the module like a library even if it is a .EXE
736 HINSTANCE16 NE_CreateInstance( NE_MODULE *pModule, HINSTANCE16 *prev,
737 BOOL32 lib_only )
739 SEGTABLEENTRY *pSegment;
740 int minsize;
741 HINSTANCE16 hNewInstance;
743 if (pModule->dgroup == 0)
745 if (prev) *prev = pModule->self;
746 return pModule->self;
749 pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
750 if (prev) *prev = SEL(pSegment->hSeg);
752 /* if it's a library, create a new instance only the first time */
753 if (pSegment->hSeg)
755 if (pModule->flags & NE_FFLAGS_LIBMODULE) return SEL(pSegment->hSeg);
756 if (lib_only) return SEL(pSegment->hSeg);
759 minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
760 if (pModule->ss == pModule->dgroup) minsize += pModule->stack_size;
761 minsize += pModule->heap_size;
762 hNewInstance = GLOBAL_Alloc( GMEM_ZEROINIT | GMEM_FIXED, minsize,
763 pModule->self, FALSE, FALSE, FALSE );
764 if (!hNewInstance) return 0;
765 pSegment->hSeg = hNewInstance;
766 pSegment->flags |= NE_SEGFLAGS_ALLOCATED;
767 return hNewInstance;
771 /***********************************************************************
772 * NE_Ne2MemFlags
774 * This function translates NE segment flags to GlobalAlloc flags
776 static WORD NE_Ne2MemFlags(WORD flags)
778 WORD memflags = 0;
779 #if 1
780 if (flags & NE_SEGFLAGS_DISCARDABLE)
781 memflags |= GMEM_DISCARDABLE;
782 if (flags & NE_SEGFLAGS_MOVEABLE ||
783 ( ! (flags & NE_SEGFLAGS_DATA) &&
784 ! (flags & NE_SEGFLAGS_LOADED) &&
785 ! (flags & NE_SEGFLAGS_ALLOCATED)
788 memflags |= GMEM_MOVEABLE;
789 memflags |= GMEM_ZEROINIT;
790 #else
791 memflags = GMEM_ZEROINIT | GMEM_FIXED;
792 #endif
793 return memflags;
796 /***********************************************************************
797 * NE_AllocateSegment (WPROCS.26)
799 DWORD WINAPI NE_AllocateSegment( WORD wFlags, WORD wSize, WORD wElem )
801 WORD size = wSize << wElem;
802 HANDLE16 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
803 return MAKELONG( hMem, GlobalHandleToSel(hMem) );
807 /***********************************************************************
808 * NE_CreateSegments
810 BOOL32 NE_CreateSegments( NE_MODULE *pModule )
812 SEGTABLEENTRY *pSegment;
813 int i, minsize;
815 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
817 pSegment = NE_SEG_TABLE( pModule );
818 for (i = 1; i <= pModule->seg_count; i++, pSegment++)
820 minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
821 if (i == pModule->ss) minsize += pModule->stack_size;
822 /* The DGROUP is allocated by NE_CreateInstance */
823 if (i == pModule->dgroup) continue;
824 pSegment->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSegment->flags),
825 minsize, pModule->self,
826 !(pSegment->flags & NE_SEGFLAGS_DATA),
827 FALSE,
828 FALSE /*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
829 if (!pSegment->hSeg) return FALSE;
830 pSegment->flags |= NE_SEGFLAGS_ALLOCATED;
833 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
834 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
835 return TRUE;
839 /**********************************************************************
840 * IsSharedSelector (KERNEL.345)
842 BOOL16 WINAPI IsSharedSelector( HANDLE16 selector )
844 /* Check whether the selector belongs to a DLL */
845 NE_MODULE *pModule = NE_GetPtr( selector );
846 if (!pModule) return FALSE;
847 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;