Initial revision
[wine/multimedia.git] / loader / ne / segment.c
blob31c8522ded4e9f8545ee5b22dcd6c5b9f5651875
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;
72 pModuleTable = NE_MODULE_TABLE( pModule );
74 if (!pSeg->filepos) return TRUE; /* No file image, just return */
76 fd = NE_OpenFile( pModule );
77 TRACE(module, "Loading segment %d, hSeg=%04x, flags=%04x\n",
78 segnum, pSeg->hSeg, pSeg->flags );
79 lseek( fd, pSeg->filepos << pModule->alignment, SEEK_SET );
80 if (pSeg->size) size = pSeg->size;
81 else if (pSeg->minsize) size = pSeg->minsize;
82 else size = 0x10000;
83 mem = GlobalLock16(pSeg->hSeg);
84 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
86 /* Implement self loading segments */
87 SELFLOADHEADER *selfloadheader;
88 STACK16FRAME *stack16Top;
89 DWORD oldstack;
90 WORD old_hSeg, new_hSeg;
91 THDB *thdb = THREAD_Current();
92 HFILE32 hf = FILE_DupUnixHandle( fd );
94 selfloadheader = (SELFLOADHEADER *)
95 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg),0);
96 oldstack = thdb->cur_stack;
97 old_hSeg = pSeg->hSeg;
98 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
99 0xff00 - sizeof(*stack16Top));
100 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
101 stack16Top->frame32 = 0;
102 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
103 stack16Top->entry_point = 0;
104 stack16Top->entry_ip = 0;
105 stack16Top->entry_cs = 0;
106 stack16Top->bp = 0;
107 stack16Top->ip = 0;
108 stack16Top->cs = 0;
109 TRACE(dll,"CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
110 pModule->self,hf,segnum );
111 new_hSeg = Callbacks->CallLoadAppSegProc(selfloadheader->LoadAppSeg,
112 pModule->self,
113 HFILE32_TO_HFILE16(hf),
114 segnum );
115 TRACE(dll,"Ret CallLoadAppSegProc: hSeg = 0x%04x\n",new_hSeg);
116 _lclose32( hf );
117 if (SEL(new_hSeg) != SEL(old_hSeg)) {
118 /* Self loaders like creating their own selectors;
119 * they love asking for trouble to Wine developers
121 if (segnum == pModule->dgroup) {
122 memcpy(PTR_SEG_OFF_TO_LIN(SEL(old_hSeg),0),
123 PTR_SEG_OFF_TO_LIN(SEL(new_hSeg),0),
124 pSeg->minsize ? pSeg->minsize : 0x10000);
125 FreeSelector(SEL(new_hSeg));
126 pSeg->hSeg = old_hSeg;
127 TRACE(module, "New hSeg allocated for dgroup segment:Old=%d,New=%d\n",
128 old_hSeg, new_hSeg);
129 } else {
130 FreeSelector(SEL(pSeg->hSeg));
131 pSeg->hSeg = new_hSeg;
135 thdb->cur_stack = oldstack;
137 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
138 read(fd, mem, size);
139 else {
141 The following bit of code for "iterated segments" was written without
142 any documentation on the format of these segments. It seems to work,
143 but may be missing something. If you have any doc please either send
144 it to me or fix the code yourself. gfm@werple.mira.net.au
146 char* buff = xmalloc(size);
147 char* curr = buff;
148 read(fd, buff, size);
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 free(buff);
163 pSeg->flags |= NE_SEGFLAGS_LOADED;
164 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
165 return TRUE; /* No relocation data, we are done */
167 read( fd, &count, sizeof(count) );
168 if (!count) return TRUE;
170 TRACE(fixup, "Fixups for %.*s, segment %d, hSeg %04x\n",
171 *((BYTE *)pModule + pModule->name_table),
172 (char *)pModule + pModule->name_table + 1,
173 segnum, pSeg->hSeg );
174 TRACE(segment, "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 );
179 reloc_entries = (struct relocation_entry_s *)xmalloc(count * sizeof(struct relocation_entry_s));
180 if (read( fd, reloc_entries, count * sizeof(struct relocation_entry_s)) !=
181 count * sizeof(struct relocation_entry_s))
183 WARN(fixup, "Unable to read relocation information\n" );
184 return FALSE;
188 * Go through the relocation table one entry at a time.
190 rep = reloc_entries;
191 for (i = 0; i < count; i++, rep++)
194 * Get the target address corresponding to this entry.
197 /* If additive, there is no target chain list. Instead, add source
198 and target */
199 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
200 rep->relocation_type &= 0x3;
202 switch (rep->relocation_type)
204 case NE_RELTYPE_ORDINAL:
205 module = pModuleTable[rep->target1-1];
206 ordinal = rep->target2;
207 address = NE_GetEntryPoint( module, ordinal );
208 if (!address)
210 NE_MODULE *pTarget = NE_GetPtr( module );
211 if (!pTarget)
212 WARN(module, "Module not found: %04x, reference %d of module %*.*s\n",
213 module, rep->target1,
214 *((BYTE *)pModule + pModule->name_table),
215 *((BYTE *)pModule + pModule->name_table),
216 (char *)pModule + pModule->name_table + 1 );
217 else
219 ERR(fixup, "No handler for %.*s.%d, setting to 0xdeadbeef\n",
220 *((BYTE *)pTarget + pTarget->name_table),
221 (char *)pTarget + pTarget->name_table + 1,
222 ordinal );
223 address = (FARPROC16)0xdeadbeef;
226 if (TRACE_ON(fixup))
228 NE_MODULE *pTarget = NE_GetPtr( module );
229 TRACE( fixup, "%d: %.*s.%d=%04x:%04x %s\n", i + 1,
230 *((BYTE *)pTarget + pTarget->name_table),
231 (char *)pTarget + pTarget->name_table + 1,
232 ordinal, HIWORD(address), LOWORD(address),
233 NE_GetRelocAddrName( rep->address_type, additive ) );
235 break;
237 case NE_RELTYPE_NAME:
238 module = pModuleTable[rep->target1-1];
239 func_name = (char *)pModule + pModule->import_table + rep->target2;
240 memcpy( buffer, func_name+1, *func_name );
241 buffer[*func_name] = '\0';
242 func_name = buffer;
243 ordinal = NE_GetOrdinal( module, func_name );
244 address = NE_GetEntryPoint( module, ordinal );
246 if (ERR_ON(fixup) && !address)
248 NE_MODULE *pTarget = NE_GetPtr( module );
249 ERR(fixup, "Warning: no handler for %.*s.%s, setting to 0xdeadbeef\n",
250 *((BYTE *)pTarget + pTarget->name_table),
251 (char *)pTarget + pTarget->name_table + 1, func_name );
253 if (!address) address = (FARPROC16) 0xdeadbeef;
254 if (TRACE_ON(fixup))
256 NE_MODULE *pTarget = NE_GetPtr( module );
257 TRACE( fixup, "%d: %.*s.%s=%04x:%04x %s\n", i + 1,
258 *((BYTE *)pTarget + pTarget->name_table),
259 (char *)pTarget + pTarget->name_table + 1,
260 func_name, HIWORD(address), LOWORD(address),
261 NE_GetRelocAddrName( rep->address_type, additive ) );
263 break;
265 case NE_RELTYPE_INTERNAL:
266 if ((rep->target1 & 0xff) == 0xff)
268 address = NE_GetEntryPoint( pModule->self, rep->target2 );
270 else
272 address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
275 TRACE( fixup,"%d: %04x:%04x %s\n",
276 i + 1, HIWORD(address), LOWORD(address),
277 NE_GetRelocAddrName( rep->address_type, additive ) );
278 break;
280 case NE_RELTYPE_OSFIXUP:
281 /* Relocation type 7:
283 * These appear to be used as fixups for the Windows
284 * floating point emulator. Let's just ignore them and
285 * try to use the hardware floating point. Linux should
286 * successfully emulate the coprocessor if it doesn't
287 * exist.
289 TRACE( fixup, "%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
290 i + 1, rep->relocation_type, rep->offset,
291 rep->target1, rep->target2,
292 NE_GetRelocAddrName( rep->address_type, additive ) );
293 continue;
296 offset = rep->offset;
298 /* Apparently, high bit of address_type is sometimes set; */
299 /* we ignore it for now */
300 if (rep->address_type > NE_RADDR_OFFSET32)
302 char module[10];
303 GetModuleName( pModule->self, module, sizeof(module) );
304 ERR( fixup, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
305 module, rep->address_type );
308 if (additive)
310 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
311 TRACE( fixup," %04x:%04x\n", offset, *sp );
312 switch (rep->address_type & 0x7f)
314 case NE_RADDR_LOWBYTE:
315 *(BYTE *)sp += LOBYTE((int)address);
316 break;
317 case NE_RADDR_OFFSET16:
318 *sp += LOWORD(address);
319 break;
320 case NE_RADDR_POINTER32:
321 *sp += LOWORD(address);
322 *(sp+1) = HIWORD(address);
323 break;
324 case NE_RADDR_SELECTOR:
325 /* Borland creates additive records with offset zero. Strange, but OK */
326 if (*sp)
327 ERR(fixup,"Additive selector to %04x.Please report\n",*sp);
328 else
329 *sp = HIWORD(address);
330 break;
331 default:
332 goto unknown;
335 else /* non-additive fixup */
339 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
340 next_offset = *sp;
341 TRACE( fixup," %04x:%04x\n", offset, *sp );
342 switch (rep->address_type & 0x7f)
344 case NE_RADDR_LOWBYTE:
345 *(BYTE *)sp = LOBYTE((int)address);
346 break;
347 case NE_RADDR_OFFSET16:
348 *sp = LOWORD(address);
349 break;
350 case NE_RADDR_POINTER32:
351 *(FARPROC16 *)sp = address;
352 break;
353 case NE_RADDR_SELECTOR:
354 *sp = SELECTOROF(address);
355 break;
356 default:
357 goto unknown;
359 if (next_offset == offset) break; /* avoid infinite loop */
360 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
361 offset = next_offset;
362 } while (offset != 0xffff);
366 free(reloc_entries);
367 return TRUE;
369 unknown:
370 WARN(fixup, "WARNING: %d: unknown ADDR TYPE %d, "
371 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
372 i + 1, rep->address_type, rep->relocation_type,
373 rep->offset, rep->target1, rep->target2);
374 free(reloc_entries);
375 return FALSE;
379 /***********************************************************************
380 * NE_LoadAllSegments
382 BOOL32 NE_LoadAllSegments( NE_MODULE *pModule )
384 int i;
386 if (pModule->flags & NE_FFLAGS_SELFLOAD)
388 HFILE32 hf;
389 /* Handle self loading modules */
390 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
391 SELFLOADHEADER *selfloadheader;
392 STACK16FRAME *stack16Top;
393 THDB *thdb = THREAD_Current();
394 HMODULE16 hselfload = GetModuleHandle16("WPROCS");
395 DWORD oldstack;
396 WORD saved_hSeg = pSegTable[pModule->dgroup - 1].hSeg;
398 TRACE(module, "%.*s is a self-loading module!\n",
399 *((BYTE*)pModule + pModule->name_table),
400 (char *)pModule + pModule->name_table + 1);
401 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
402 selfloadheader = (SELFLOADHEADER *)
403 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg), 0);
404 selfloadheader->EntryAddrProc = NE_GetEntryPoint(hselfload,27);
405 selfloadheader->MyAlloc = NE_GetEntryPoint(hselfload,28);
406 selfloadheader->SetOwner = NE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
407 pModule->self_loading_sel = GlobalHandleToSel(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
408 oldstack = thdb->cur_stack;
409 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
410 0xff00 - sizeof(*stack16Top) );
411 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
412 stack16Top->frame32 = 0;
413 stack16Top->ebp = 0;
414 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
415 stack16Top->entry_point = 0;
416 stack16Top->entry_ip = 0;
417 stack16Top->entry_cs = 0;
418 stack16Top->bp = 0;
419 stack16Top->ip = 0;
420 stack16Top->cs = 0;
422 hf = FILE_DupUnixHandle( NE_OpenFile( pModule ) );
423 TRACE(dll,"CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",pModule->self,
424 HFILE32_TO_HFILE16(hf));
425 Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self,
426 HFILE32_TO_HFILE16(hf));
427 TRACE(dll,"Return from CallBootAppProc\n");
428 _lclose32(hf);
429 /* some BootApp procs overwrite the segment handle of dgroup */
430 pSegTable[pModule->dgroup - 1].hSeg = saved_hSeg;
431 thdb->cur_stack = oldstack;
433 /* FIXME
434 commented out by Andreas Mohr;
435 some self-loading exe ("BLINKER") relies on non-primary segs not loaded.
436 contact me if you experience problems */
437 /*for (i = 2; i <= pModule->seg_count; i++)
438 if (!NE_LoadSegment( pModule, i )) return FALSE;*/
440 else
442 for (i = 1; i <= pModule->seg_count; i++)
443 if (!NE_LoadSegment( pModule, i )) return FALSE;
445 return TRUE;
449 /***********************************************************************
450 * NE_FixupPrologs
452 * Fixup the exported functions prologs.
454 void NE_FixupPrologs( NE_MODULE *pModule )
456 SEGTABLEENTRY *pSegTable;
457 WORD dgroup = 0;
458 WORD sel;
459 BYTE *p, *fixup_ptr, count;
460 dbg_decl_str(module, 512);
462 pSegTable = NE_SEG_TABLE(pModule);
463 if (pModule->flags & NE_FFLAGS_SINGLEDATA)
464 dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg);
466 TRACE(module, "(%04x)\n", pModule->self );
467 p = (BYTE *)pModule + pModule->entry_table;
468 while (*p)
470 if (p[1] == 0) /* Unused entry */
472 p += 2; /* Skip it */
473 continue;
475 if (p[1] == 0xfe) /* Constant entry */
477 p += 2 + *p * 3; /* Skip it */
478 continue;
481 /* Now fixup the entries of this bundle */
482 count = *p;
483 sel = p[1];
484 p += 2;
485 while (count-- > 0)
487 dbg_reset_str(module);
488 dsprintf(module,"Flags: %04x, sel %02x ", *p, sel);
489 /* According to the output generated by TDUMP, the flags mean:
490 * 0x0001 function is exported
491 * 0x0002 Single data (seems to occur only in DLLs)
493 if (sel == 0xff) { /* moveable */
494 dsprintf(module, "(%02x) o %04x", p[3], *(WORD *)(p+4) );
495 fixup_ptr = (char *)GET_SEL_BASE(SEL(pSegTable[p[3]-1].hSeg)) + *(WORD *)(p + 4);
496 } else { /* fixed */
497 dsprintf(module, "offset %04x", *(WORD *)(p+1) );
498 fixup_ptr = (char *)GET_SEL_BASE(SEL(pSegTable[sel-1].hSeg)) +
499 *(WORD *)(p + 1);
501 TRACE(module, "%s Signature: %02x %02x %02x,ff %x\n",
502 dbg_str(module), fixup_ptr[0], fixup_ptr[1],
503 fixup_ptr[2], pModule->flags );
504 if (*p & 0x0001)
506 /* Verify the signature */
507 if (((fixup_ptr[0] == 0x1e && fixup_ptr[1] == 0x58)
508 || (fixup_ptr[0] == 0x8c && fixup_ptr[1] == 0xd8))
509 && fixup_ptr[2] == 0x90)
511 if (*p & 0x0002)
513 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA)
515 /* can this happen? */
516 ERR(fixup, "FixupPrologs got confused\n" );
518 else if (pModule->flags & NE_FFLAGS_SINGLEDATA)
520 *fixup_ptr = 0xb8; /* MOV AX, */
521 *(WORD *)(fixup_ptr+1) = dgroup;
524 else
526 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA) {
527 fixup_ptr[0] = 0x90; /* non-library: NOPs */
528 fixup_ptr[1] = 0x90;
529 fixup_ptr[2] = 0x90;
532 } else {
533 WARN(fixup, "Unknown signature\n" );
536 else
537 TRACE(module,"\n");
538 p += (sel == 0xff) ? 6 : 3;
543 /***********************************************************************
544 * NE_GetDLLInitParams
546 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
547 WORD *hInst, WORD *ds, WORD *heap )
549 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
551 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
553 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
555 /* Not SINGLEDATA */
556 ERR(dll, "Library is not marked SINGLEDATA\n");
557 exit(1);
559 else /* DATA NONE DLL */
561 *ds = 0;
562 *heap = 0;
565 else /* DATA SINGLE DLL */
567 if (pModule->dgroup) {
568 *ds = SEL(pSegTable[pModule->dgroup-1].hSeg);
569 *heap = pModule->heap_size;
571 else /* hmm, DLL has no dgroup,
572 but why has it NE_FFLAGS_SINGLEDATA set ?
573 Buggy DLL compiler ? */
575 *ds = 0;
576 *heap = 0;
580 *hInst = *ds ? *ds : pModule->self;
584 /***********************************************************************
585 * NE_InitDLL
587 * Call the DLL initialization code
589 static BOOL32 NE_InitDLL( TDB* pTask, NE_MODULE *pModule )
591 SEGTABLEENTRY *pSegTable;
592 WORD hInst, ds, heap;
593 CONTEXT context;
595 pSegTable = NE_SEG_TABLE( pModule );
597 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
598 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
600 /* Call USER signal handler. This is necessary to install a
601 * proper loader for HICON and HCURSOR resources that this DLL
602 * may contain. InitApp() does this for task modules. */
604 if (pTask && pTask->userhandler)
606 pTask->userhandler( pModule->self, USIG_DLL_LOAD, 0, pTask->hInstance,
607 pTask->hQueue );
610 if (!pModule->cs) return TRUE; /* no initialization code */
613 /* Registers at initialization must be:
614 * cx heap size
615 * di library instance
616 * ds data segment if any
617 * es:si command line (always 0)
620 memset( &context, 0, sizeof(context) );
622 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
624 ECX_reg(&context) = heap;
625 EDI_reg(&context) = hInst;
626 DS_reg(&context) = ds;
627 ES_reg(&context) = ds; /* who knows ... */
629 CS_reg(&context) = SEL(pSegTable[pModule->cs-1].hSeg);
630 EIP_reg(&context) = pModule->ip;
631 EBP_reg(&context) = OFFSETOF(THREAD_Current()->cur_stack)
632 + (WORD)&((STACK16FRAME*)0)->bp;
635 pModule->cs = 0; /* Don't initialize it twice */
636 TRACE(dll, "Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
637 CS_reg(&context), IP_reg(&context), DS_reg(&context),
638 DI_reg(&context), CX_reg(&context) );
639 Callbacks->CallRegisterShortProc( &context, 0 );
640 return TRUE;
643 /***********************************************************************
644 * NE_CallDllEntryPoint
646 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
649 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
651 WORD hInst, ds, heap;
652 FARPROC16 entryPoint;
653 WORD ordinal;
654 CONTEXT context;
655 THDB *thdb = THREAD_Current();
656 LPBYTE stack = (LPBYTE)THREAD_STACK16(thdb);
658 if (pModule->expected_version < 0x0400) return;
659 if (!(ordinal = NE_GetOrdinal( pModule->self, "DllEntryPoint" ))) return;
660 if (!(entryPoint = NE_GetEntryPoint( pModule->self, ordinal ))) return;
662 memset( &context, 0, sizeof(context) );
664 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
666 DS_reg(&context) = ds;
667 ES_reg(&context) = ds; /* who knows ... */
669 CS_reg(&context) = HIWORD(entryPoint);
670 IP_reg(&context) = LOWORD(entryPoint);
671 EBP_reg(&context) = OFFSETOF( thdb->cur_stack )
672 + (WORD)&((STACK16FRAME*)0)->bp;
674 *(DWORD *)(stack - 4) = dwReason; /* dwReason */
675 *(WORD *) (stack - 6) = hInst; /* hInst */
676 *(WORD *) (stack - 8) = ds; /* wDS */
677 *(WORD *) (stack - 10) = heap; /* wHeapSize */
678 *(DWORD *)(stack - 14) = 0; /* dwReserved1 */
679 *(WORD *) (stack - 16) = 0; /* wReserved2 */
681 TRACE(dll, "Calling DllEntryPoint, cs:ip=%04lx:%04x\n",
682 CS_reg(&context), IP_reg(&context));
684 Callbacks->CallRegisterShortProc( &context, 16 );
688 /***********************************************************************
689 * NE_InitializeDLLs
691 * Recursively initialize all DLLs (according to the order in which
692 * they where loaded).
694 void NE_InitializeDLLs( HMODULE16 hModule )
696 TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
697 NE_MODULE *pModule;
698 HMODULE16 *pDLL;
700 if (!(pModule = NE_GetPtr( hModule ))) return;
701 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
703 if (pModule->dlls_to_init)
705 HGLOBAL16 to_init = pModule->dlls_to_init;
706 pModule->dlls_to_init = 0;
707 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
709 NE_InitializeDLLs( *pDLL );
711 GlobalFree16( to_init );
713 NE_InitDLL( pTask, pModule );
714 NE_CallDllEntryPoint( pModule, DLL_PROCESS_ATTACH );
718 /***********************************************************************
719 * NE_CreateInstance
721 * If lib_only is TRUE, handle the module like a library even if it is a .EXE
723 HINSTANCE16 NE_CreateInstance( NE_MODULE *pModule, HINSTANCE16 *prev,
724 BOOL32 lib_only )
726 SEGTABLEENTRY *pSegment;
727 int minsize;
728 HINSTANCE16 hNewInstance;
730 if (pModule->dgroup == 0)
732 if (prev) *prev = pModule->self;
733 return pModule->self;
736 pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
737 if (prev) *prev = SEL(pSegment->hSeg);
739 /* if it's a library, create a new instance only the first time */
740 if (pSegment->hSeg)
742 if (pModule->flags & NE_FFLAGS_LIBMODULE) return SEL(pSegment->hSeg);
743 if (lib_only) return SEL(pSegment->hSeg);
746 minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
747 if (pModule->ss == pModule->dgroup) minsize += pModule->stack_size;
748 minsize += pModule->heap_size;
749 hNewInstance = GLOBAL_Alloc( GMEM_ZEROINIT | GMEM_FIXED, minsize,
750 pModule->self, FALSE, FALSE, FALSE );
751 if (!hNewInstance) return 0;
752 pSegment->hSeg = hNewInstance;
753 pSegment->flags |= NE_SEGFLAGS_ALLOCATED;
754 return hNewInstance;
758 /***********************************************************************
759 * PatchCodeHandle
761 * Needed for self-loading modules.
764 /* It does nothing */
765 void WINAPI PatchCodeHandle(HANDLE16 hSel)
767 FIXME(module,"(%04x): stub.\n",hSel);
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;