Optimized include/*.h: (recursively) include all headers needed by
[wine/testsucceed.git] / loader / ne / segment.c
blob0fd0605e1244339ebdc649a68c03b11e58a0991f
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 "debug.h"
29 #include "xmalloc.h"
31 #define SEL(x) GlobalHandleToSel(x)
33 /***********************************************************************
34 * NE_GetRelocAddrName
36 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
38 switch(addr_type & 0x7f)
40 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
41 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
42 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
43 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
44 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
45 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
47 return "???";
51 /***********************************************************************
52 * NE_LoadSegment
54 BOOL32 NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
56 SEGTABLEENTRY *pSegTable, *pSeg;
57 WORD *pModuleTable;
58 WORD count, i, offset, next_offset;
59 HMODULE16 module;
60 FARPROC16 address = 0;
61 HFILE32 hf;
62 DWORD res;
63 struct relocation_entry_s *rep, *reloc_entries;
64 BYTE *func_name;
65 int size;
66 char* mem;
68 char buffer[256];
69 int ordinal, additive;
70 unsigned short *sp;
72 pSegTable = NE_SEG_TABLE( pModule );
73 pSeg = pSegTable + segnum - 1;
75 if (pSeg->flags & NE_SEGFLAGS_LOADED) /* already loaded ? */
76 return TRUE;
78 if (!pSeg->filepos) return TRUE; /* No file image, just return */
80 pModuleTable = NE_MODULE_TABLE( pModule );
82 hf = NE_OpenFile( pModule );
83 TRACE(module, "Loading segment %d, hSeg=%04x, flags=%04x\n",
84 segnum, pSeg->hSeg, pSeg->flags );
85 SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
86 if (pSeg->size) size = pSeg->size;
87 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
88 mem = GlobalLock16(pSeg->hSeg);
89 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
91 /* Implement self loading segments */
92 SELFLOADHEADER *selfloadheader;
93 STACK16FRAME *stack16Top;
94 DWORD oldstack;
95 WORD old_hSeg, new_hSeg;
96 THDB *thdb = THREAD_Current();
97 HFILE32 hFile32;
98 HFILE16 hFile16;
100 selfloadheader = (SELFLOADHEADER *)
101 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg),0);
102 oldstack = thdb->cur_stack;
103 old_hSeg = pSeg->hSeg;
104 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
105 0xff00 - sizeof(*stack16Top));
106 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
107 stack16Top->frame32 = 0;
108 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
109 stack16Top->entry_point = 0;
110 stack16Top->entry_ip = 0;
111 stack16Top->entry_cs = 0;
112 stack16Top->bp = 0;
113 stack16Top->ip = 0;
114 stack16Top->cs = 0;
115 TRACE(dll,"CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
116 pModule->self,hf,segnum );
117 DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
118 0, FALSE, DUPLICATE_SAME_ACCESS );
119 hFile16 = FILE_AllocDosHandle( hFile32 );
120 new_hSeg = Callbacks->CallLoadAppSegProc(selfloadheader->LoadAppSeg,
121 pModule->self, hFile16,
122 segnum );
123 TRACE(dll,"Ret CallLoadAppSegProc: hSeg = 0x%04x\n",new_hSeg);
124 _lclose16( hFile16 );
125 if (SEL(new_hSeg) != SEL(old_hSeg)) {
126 /* Self loaders like creating their own selectors;
127 * they love asking for trouble to Wine developers
129 if (segnum == pModule->dgroup) {
130 memcpy(PTR_SEG_OFF_TO_LIN(SEL(old_hSeg),0),
131 PTR_SEG_OFF_TO_LIN(SEL(new_hSeg),0),
132 pSeg->minsize ? pSeg->minsize : 0x10000);
133 FreeSelector(SEL(new_hSeg));
134 pSeg->hSeg = old_hSeg;
135 TRACE(module, "New hSeg allocated for dgroup segment:Old=%d,New=%d\n",
136 old_hSeg, new_hSeg);
137 } else {
138 FreeSelector(SEL(pSeg->hSeg));
139 pSeg->hSeg = new_hSeg;
143 thdb->cur_stack = oldstack;
145 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
146 ReadFile(hf, mem, size, &res, NULL);
147 else {
149 The following bit of code for "iterated segments" was written without
150 any documentation on the format of these segments. It seems to work,
151 but may be missing something. If you have any doc please either send
152 it to me or fix the code yourself. gfm@werple.mira.net.au
154 char* buff = xmalloc(size);
155 char* curr = buff;
156 ReadFile(hf, buff, size, &res, NULL);
157 while(curr < buff + size) {
158 unsigned int rept = *((short*) curr)++;
159 unsigned int len = *((short*) curr)++;
160 for(; rept > 0; rept--) {
161 char* bytes = curr;
162 unsigned int byte;
163 for(byte = 0; byte < len; byte++)
164 *mem++ = *bytes++;
166 curr += len;
168 free(buff);
171 pSeg->flags |= NE_SEGFLAGS_LOADED;
172 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
173 return TRUE; /* No relocation data, we are done */
175 ReadFile(hf, &count, sizeof(count), &res, NULL);
176 if (!count) return TRUE;
178 TRACE(fixup, "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 );
182 TRACE(segment, "Fixups for %.*s, segment %d, hSeg %04x\n",
183 *((BYTE *)pModule + pModule->name_table),
184 (char *)pModule + pModule->name_table + 1,
185 segnum, pSeg->hSeg );
187 reloc_entries = (struct relocation_entry_s *)xmalloc(count * sizeof(struct relocation_entry_s));
188 if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
189 (res != count * sizeof(struct relocation_entry_s)))
191 WARN(fixup, "Unable to read relocation information\n" );
192 return FALSE;
196 * Go through the relocation table one entry at a time.
198 rep = reloc_entries;
199 for (i = 0; i < count; i++, rep++)
202 * Get the target address corresponding to this entry.
205 /* If additive, there is no target chain list. Instead, add source
206 and target */
207 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
208 rep->relocation_type &= 0x3;
210 switch (rep->relocation_type)
212 case NE_RELTYPE_ORDINAL:
213 module = pModuleTable[rep->target1-1];
214 ordinal = rep->target2;
215 address = NE_GetEntryPoint( module, ordinal );
216 if (!address)
218 NE_MODULE *pTarget = NE_GetPtr( module );
219 if (!pTarget)
220 WARN(module, "Module not found: %04x, reference %d of module %*.*s\n",
221 module, rep->target1,
222 *((BYTE *)pModule + pModule->name_table),
223 *((BYTE *)pModule + pModule->name_table),
224 (char *)pModule + pModule->name_table + 1 );
225 else
227 ERR(fixup, "No implementation for %.*s.%d, setting to 0xdeadbeef\n",
228 *((BYTE *)pTarget + pTarget->name_table),
229 (char *)pTarget + pTarget->name_table + 1,
230 ordinal );
231 address = (FARPROC16)0xdeadbeef;
234 if (TRACE_ON(fixup))
236 NE_MODULE *pTarget = NE_GetPtr( module );
237 TRACE( fixup, "%d: %.*s.%d=%04x:%04x %s\n", i + 1,
238 *((BYTE *)pTarget + pTarget->name_table),
239 (char *)pTarget + pTarget->name_table + 1,
240 ordinal, HIWORD(address), LOWORD(address),
241 NE_GetRelocAddrName( rep->address_type, additive ) );
243 break;
245 case NE_RELTYPE_NAME:
246 module = pModuleTable[rep->target1-1];
247 func_name = (char *)pModule + pModule->import_table + rep->target2;
248 memcpy( buffer, func_name+1, *func_name );
249 buffer[*func_name] = '\0';
250 func_name = buffer;
251 ordinal = NE_GetOrdinal( module, func_name );
252 address = NE_GetEntryPoint( module, ordinal );
254 if (ERR_ON(fixup) && !address)
256 NE_MODULE *pTarget = NE_GetPtr( module );
257 ERR(fixup, "No implementation for %.*s.%s, setting to 0xdeadbeef\n",
258 *((BYTE *)pTarget + pTarget->name_table),
259 (char *)pTarget + pTarget->name_table + 1, func_name );
261 if (!address) address = (FARPROC16) 0xdeadbeef;
262 if (TRACE_ON(fixup))
264 NE_MODULE *pTarget = NE_GetPtr( module );
265 TRACE( fixup, "%d: %.*s.%s=%04x:%04x %s\n", i + 1,
266 *((BYTE *)pTarget + pTarget->name_table),
267 (char *)pTarget + pTarget->name_table + 1,
268 func_name, HIWORD(address), LOWORD(address),
269 NE_GetRelocAddrName( rep->address_type, additive ) );
271 break;
273 case NE_RELTYPE_INTERNAL:
274 if ((rep->target1 & 0xff) == 0xff)
276 address = NE_GetEntryPoint( pModule->self, rep->target2 );
278 else
280 address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
283 TRACE( fixup,"%d: %04x:%04x %s\n",
284 i + 1, HIWORD(address), LOWORD(address),
285 NE_GetRelocAddrName( rep->address_type, additive ) );
286 break;
288 case NE_RELTYPE_OSFIXUP:
289 /* Relocation type 7:
291 * These appear to be used as fixups for the Windows
292 * floating point emulator. Let's just ignore them and
293 * try to use the hardware floating point. Linux should
294 * successfully emulate the coprocessor if it doesn't
295 * exist.
297 TRACE( fixup, "%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
298 i + 1, rep->relocation_type, rep->offset,
299 rep->target1, rep->target2,
300 NE_GetRelocAddrName( rep->address_type, additive ) );
301 continue;
304 offset = rep->offset;
306 /* Apparently, high bit of address_type is sometimes set; */
307 /* we ignore it for now */
308 if (rep->address_type > NE_RADDR_OFFSET32)
310 char module[10];
311 GetModuleName( pModule->self, module, sizeof(module) );
312 ERR( fixup, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
313 module, rep->address_type );
316 if (additive)
318 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
319 TRACE( fixup," %04x:%04x\n", offset, *sp );
320 switch (rep->address_type & 0x7f)
322 case NE_RADDR_LOWBYTE:
323 *(BYTE *)sp += LOBYTE((int)address);
324 break;
325 case NE_RADDR_OFFSET16:
326 *sp += LOWORD(address);
327 break;
328 case NE_RADDR_POINTER32:
329 *sp += LOWORD(address);
330 *(sp+1) = HIWORD(address);
331 break;
332 case NE_RADDR_SELECTOR:
333 /* Borland creates additive records with offset zero. Strange, but OK */
334 if (*sp)
335 ERR(fixup,"Additive selector to %04x.Please report\n",*sp);
336 else
337 *sp = HIWORD(address);
338 break;
339 default:
340 goto unknown;
343 else /* non-additive fixup */
347 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
348 next_offset = *sp;
349 TRACE( fixup," %04x:%04x\n", offset, *sp );
350 switch (rep->address_type & 0x7f)
352 case NE_RADDR_LOWBYTE:
353 *(BYTE *)sp = LOBYTE((int)address);
354 break;
355 case NE_RADDR_OFFSET16:
356 *sp = LOWORD(address);
357 break;
358 case NE_RADDR_POINTER32:
359 *(FARPROC16 *)sp = address;
360 break;
361 case NE_RADDR_SELECTOR:
362 *sp = SELECTOROF(address);
363 break;
364 default:
365 goto unknown;
367 if (next_offset == offset) break; /* avoid infinite loop */
368 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
369 offset = next_offset;
370 } while (offset != 0xffff);
374 free(reloc_entries);
375 return TRUE;
377 unknown:
378 WARN(fixup, "WARNING: %d: unknown ADDR TYPE %d, "
379 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
380 i + 1, rep->address_type, rep->relocation_type,
381 rep->offset, rep->target1, rep->target2);
382 free(reloc_entries);
383 return FALSE;
387 /***********************************************************************
388 * NE_LoadAllSegments
390 BOOL32 NE_LoadAllSegments( NE_MODULE *pModule )
392 int i;
393 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
395 if (pModule->flags & NE_FFLAGS_SELFLOAD)
397 HFILE32 hf;
398 HFILE16 hFile16;
399 /* Handle self loading modules */
400 SELFLOADHEADER *selfloadheader;
401 STACK16FRAME *stack16Top;
402 THDB *thdb = THREAD_Current();
403 HMODULE16 hselfload = GetModuleHandle16("WPROCS");
404 DWORD oldstack;
405 WORD saved_hSeg = pSegTable[pModule->dgroup - 1].hSeg;
407 TRACE(module, "%.*s is a self-loading module!\n",
408 *((BYTE*)pModule + pModule->name_table),
409 (char *)pModule + pModule->name_table + 1);
410 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
411 selfloadheader = (SELFLOADHEADER *)
412 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg), 0);
413 selfloadheader->EntryAddrProc = NE_GetEntryPoint(hselfload,27);
414 selfloadheader->MyAlloc = NE_GetEntryPoint(hselfload,28);
415 selfloadheader->SetOwner = NE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
416 pModule->self_loading_sel = GlobalHandleToSel(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
417 oldstack = thdb->cur_stack;
418 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
419 0xff00 - sizeof(*stack16Top) );
420 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
421 stack16Top->frame32 = 0;
422 stack16Top->ebp = 0;
423 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
424 stack16Top->entry_point = 0;
425 stack16Top->entry_ip = 0;
426 stack16Top->entry_cs = 0;
427 stack16Top->bp = 0;
428 stack16Top->ip = 0;
429 stack16Top->cs = 0;
431 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule),
432 GetCurrentProcess(), &hf, 0, FALSE, DUPLICATE_SAME_ACCESS );
433 hFile16 = FILE_AllocDosHandle( hf );
434 TRACE(dll,"CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
435 pModule->self,hFile16);
436 Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self,hFile16);
437 TRACE(dll,"Return from CallBootAppProc\n");
438 _lclose16(hf);
439 /* some BootApp procs overwrite the segment handle of dgroup */
440 pSegTable[pModule->dgroup - 1].hSeg = saved_hSeg;
441 thdb->cur_stack = oldstack;
443 for (i = 2; i <= pModule->seg_count; i++)
444 if (!NE_LoadSegment( pModule, i )) return FALSE;
446 else
448 for (i = 1; i <= pModule->seg_count; i++)
449 if (!NE_LoadSegment( pModule, i )) return FALSE;
451 return TRUE;
455 /***********************************************************************
456 * PatchCodeHandle
458 * Needed for self-loading modules.
461 /* It does nothing */
462 DWORD WINAPI PatchCodeHandle(HANDLE16 hSel)
464 FIXME(module,"(%04x): stub.\n",hSel);
465 return (DWORD)NULL;
469 /***********************************************************************
470 * NE_FixupPrologs
472 * Fixup the exported functions prologs.
474 void NE_FixupPrologs( NE_MODULE *pModule )
476 SEGTABLEENTRY *pSegTable;
477 WORD dgroup = 0;
478 WORD sel;
479 BYTE *p, *fixup_ptr, count;
480 dbg_decl_str(module, 512);
482 pSegTable = NE_SEG_TABLE(pModule);
483 if (pModule->flags & NE_FFLAGS_SINGLEDATA)
484 dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg);
486 TRACE(module, "(%04x)\n", pModule->self );
487 p = (BYTE *)pModule + pModule->entry_table;
488 while (*p)
490 if (p[1] == 0) /* Unused entry */
492 p += 2; /* Skip it */
493 continue;
495 if (p[1] == 0xfe) /* Constant entry */
497 p += 2 + *p * 3; /* Skip it */
498 continue;
501 /* Now fixup the entries of this bundle */
502 count = *p;
503 sel = p[1];
504 p += 2;
505 while (count-- > 0)
507 dbg_reset_str(module);
508 dsprintf(module,"Flags: %04x, sel %02x ", *p, sel);
509 /* According to the output generated by TDUMP, the flags mean:
510 * 0x0001 function is exported
511 * 0x0002 Single data (seems to occur only in DLLs)
513 if (sel == 0xff) { /* moveable */
514 dsprintf(module, "(%02x) o %04x", p[3], *(WORD *)(p+4) );
515 fixup_ptr = (char *)GET_SEL_BASE(SEL(pSegTable[p[3]-1].hSeg)) + *(WORD *)(p + 4);
516 } else { /* fixed */
517 dsprintf(module, "offset %04x", *(WORD *)(p+1) );
518 fixup_ptr = (char *)GET_SEL_BASE(SEL(pSegTable[sel-1].hSeg)) +
519 *(WORD *)(p + 1);
521 TRACE(module, "%s Signature: %02x %02x %02x,ff %x\n",
522 dbg_str(module), fixup_ptr[0], fixup_ptr[1],
523 fixup_ptr[2], pModule->flags );
524 if (*p & 0x0001)
526 /* Verify the signature */
527 if (((fixup_ptr[0] == 0x1e && fixup_ptr[1] == 0x58)
528 || (fixup_ptr[0] == 0x8c && fixup_ptr[1] == 0xd8))
529 && fixup_ptr[2] == 0x90)
531 if (*p & 0x0002)
533 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA)
535 /* can this happen? */
536 ERR(fixup, "FixupPrologs got confused\n" );
538 else if (pModule->flags & NE_FFLAGS_SINGLEDATA)
540 *fixup_ptr = 0xb8; /* MOV AX, */
541 *(WORD *)(fixup_ptr+1) = dgroup;
544 else
546 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA) {
547 fixup_ptr[0] = 0x90; /* non-library: NOPs */
548 fixup_ptr[1] = 0x90;
549 fixup_ptr[2] = 0x90;
552 } else {
553 WARN(fixup, "Unknown signature\n" );
556 else
557 TRACE(module,"\n");
558 p += (sel == 0xff) ? 6 : 3;
563 /***********************************************************************
564 * NE_GetDLLInitParams
566 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
567 WORD *hInst, WORD *ds, WORD *heap )
569 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
571 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
573 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
575 /* Not SINGLEDATA */
576 ERR(dll, "Library is not marked SINGLEDATA\n");
577 exit(1);
579 else /* DATA NONE DLL */
581 *ds = 0;
582 *heap = 0;
585 else /* DATA SINGLE DLL */
587 if (pModule->dgroup) {
588 *ds = SEL(pSegTable[pModule->dgroup-1].hSeg);
589 *heap = pModule->heap_size;
591 else /* hmm, DLL has no dgroup,
592 but why has it NE_FFLAGS_SINGLEDATA set ?
593 Buggy DLL compiler ? */
595 *ds = 0;
596 *heap = 0;
600 *hInst = *ds ? *ds : pModule->self;
604 /***********************************************************************
605 * NE_InitDLL
607 * Call the DLL initialization code
609 static BOOL32 NE_InitDLL( TDB* pTask, NE_MODULE *pModule )
611 SEGTABLEENTRY *pSegTable;
612 WORD hInst, ds, heap;
613 CONTEXT context;
615 pSegTable = NE_SEG_TABLE( pModule );
617 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
618 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
620 /* Call USER signal handler. This is necessary to install a
621 * proper loader for HICON and HCURSOR resources that this DLL
622 * may contain. InitApp() does this for task modules. */
624 if (pTask && pTask->userhandler)
626 pTask->userhandler( pModule->self, USIG_DLL_LOAD, 0, pTask->hInstance,
627 pTask->hQueue );
630 if (!pModule->cs) return TRUE; /* no initialization code */
633 /* Registers at initialization must be:
634 * cx heap size
635 * di library instance
636 * ds data segment if any
637 * es:si command line (always 0)
640 memset( &context, 0, sizeof(context) );
642 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
644 ECX_reg(&context) = heap;
645 EDI_reg(&context) = hInst;
646 DS_reg(&context) = ds;
647 ES_reg(&context) = ds; /* who knows ... */
649 CS_reg(&context) = SEL(pSegTable[pModule->cs-1].hSeg);
650 EIP_reg(&context) = pModule->ip;
651 EBP_reg(&context) = OFFSETOF(THREAD_Current()->cur_stack)
652 + (WORD)&((STACK16FRAME*)0)->bp;
655 pModule->cs = 0; /* Don't initialize it twice */
656 TRACE(dll, "Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
657 CS_reg(&context), IP_reg(&context), DS_reg(&context),
658 DI_reg(&context), CX_reg(&context) );
659 Callbacks->CallRegisterShortProc( &context, 0 );
660 return TRUE;
663 /***********************************************************************
664 * NE_CallDllEntryPoint
666 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
669 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
671 WORD hInst, ds, heap;
672 FARPROC16 entryPoint;
673 WORD ordinal;
674 CONTEXT context;
675 THDB *thdb = THREAD_Current();
676 LPBYTE stack = (LPBYTE)THREAD_STACK16(thdb);
678 if (pModule->expected_version < 0x0400) return;
679 if (!(ordinal = NE_GetOrdinal( pModule->self, "DllEntryPoint" ))) return;
680 if (!(entryPoint = NE_GetEntryPoint( pModule->self, ordinal ))) return;
682 memset( &context, 0, sizeof(context) );
684 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
686 DS_reg(&context) = ds;
687 ES_reg(&context) = ds; /* who knows ... */
689 CS_reg(&context) = HIWORD(entryPoint);
690 IP_reg(&context) = LOWORD(entryPoint);
691 EBP_reg(&context) = OFFSETOF( thdb->cur_stack )
692 + (WORD)&((STACK16FRAME*)0)->bp;
694 *(DWORD *)(stack - 4) = dwReason; /* dwReason */
695 *(WORD *) (stack - 6) = hInst; /* hInst */
696 *(WORD *) (stack - 8) = ds; /* wDS */
697 *(WORD *) (stack - 10) = heap; /* wHeapSize */
698 *(DWORD *)(stack - 14) = 0; /* dwReserved1 */
699 *(WORD *) (stack - 16) = 0; /* wReserved2 */
701 TRACE(dll, "Calling DllEntryPoint, cs:ip=%04lx:%04x\n",
702 CS_reg(&context), IP_reg(&context));
704 Callbacks->CallRegisterShortProc( &context, 16 );
708 /***********************************************************************
709 * NE_InitializeDLLs
711 * Recursively initialize all DLLs (according to the order in which
712 * they where loaded).
714 void NE_InitializeDLLs( HMODULE16 hModule )
716 TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
717 NE_MODULE *pModule;
718 HMODULE16 *pDLL;
720 if (!(pModule = NE_GetPtr( hModule ))) return;
721 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
723 if (pModule->dlls_to_init)
725 HGLOBAL16 to_init = pModule->dlls_to_init;
726 pModule->dlls_to_init = 0;
727 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
729 NE_InitializeDLLs( *pDLL );
731 GlobalFree16( to_init );
733 NE_InitDLL( pTask, pModule );
734 NE_CallDllEntryPoint( pModule, DLL_PROCESS_ATTACH );
738 /***********************************************************************
739 * NE_CreateInstance
741 * If lib_only is TRUE, handle the module like a library even if it is a .EXE
743 HINSTANCE16 NE_CreateInstance( NE_MODULE *pModule, HINSTANCE16 *prev,
744 BOOL32 lib_only )
746 SEGTABLEENTRY *pSegment;
747 int minsize;
748 HINSTANCE16 hNewInstance;
750 if (pModule->dgroup == 0)
752 if (prev) *prev = pModule->self;
753 return pModule->self;
756 pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
757 if (prev) *prev = SEL(pSegment->hSeg);
759 /* if it's a library, create a new instance only the first time */
760 if (pSegment->hSeg)
762 if (pModule->flags & NE_FFLAGS_LIBMODULE) return SEL(pSegment->hSeg);
763 if (lib_only) return SEL(pSegment->hSeg);
766 minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
767 if (pModule->ss == pModule->dgroup) minsize += pModule->stack_size;
768 minsize += pModule->heap_size;
769 hNewInstance = GLOBAL_Alloc( GMEM_ZEROINIT | GMEM_FIXED, minsize,
770 pModule->self, FALSE, FALSE, FALSE );
771 if (!hNewInstance) return 0;
772 pSegment->hSeg = hNewInstance;
773 pSegment->flags |= NE_SEGFLAGS_ALLOCATED;
774 return hNewInstance;
778 /***********************************************************************
779 * NE_Ne2MemFlags
781 * This function translates NE segment flags to GlobalAlloc flags
783 static WORD NE_Ne2MemFlags(WORD flags)
785 WORD memflags = 0;
786 #if 1
787 if (flags & NE_SEGFLAGS_DISCARDABLE)
788 memflags |= GMEM_DISCARDABLE;
789 if (flags & NE_SEGFLAGS_MOVEABLE ||
790 ( ! (flags & NE_SEGFLAGS_DATA) &&
791 ! (flags & NE_SEGFLAGS_LOADED) &&
792 ! (flags & NE_SEGFLAGS_ALLOCATED)
795 memflags |= GMEM_MOVEABLE;
796 memflags |= GMEM_ZEROINIT;
797 #else
798 memflags = GMEM_ZEROINIT | GMEM_FIXED;
799 #endif
800 return memflags;
803 /***********************************************************************
804 * NE_AllocateSegment (WPROCS.26)
806 DWORD WINAPI NE_AllocateSegment( WORD wFlags, WORD wSize, WORD wElem )
808 WORD size = wSize << wElem;
809 HANDLE16 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
811 /* not data == code */
812 if ( (wFlags & NE_SEGFLAGS_EXECUTEONLY) ||
813 !(wFlags & NE_SEGFLAGS_DATA)
815 WORD hSel = GlobalHandleToSel(hMem);
816 WORD access = SelectorAccessRights(hSel,0,0);
818 access |= 2<<2; /* SEGMENT_CODE */
819 SelectorAccessRights(hSel,1,access);
821 return MAKELONG( hMem, GlobalHandleToSel(hMem) );
825 /***********************************************************************
826 * NE_CreateSegments
828 BOOL32 NE_CreateSegments( NE_MODULE *pModule )
830 SEGTABLEENTRY *pSegment;
831 int i, minsize;
833 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
835 pSegment = NE_SEG_TABLE( pModule );
836 for (i = 1; i <= pModule->seg_count; i++, pSegment++)
838 minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
839 if (i == pModule->ss) minsize += pModule->stack_size;
840 /* The DGROUP is allocated by NE_CreateInstance */
841 if (i == pModule->dgroup) continue;
842 pSegment->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSegment->flags),
843 minsize, pModule->self,
844 !(pSegment->flags & NE_SEGFLAGS_DATA),
845 FALSE,
846 FALSE /*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
847 if (!pSegment->hSeg) return FALSE;
848 pSegment->flags |= NE_SEGFLAGS_ALLOCATED;
851 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
852 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
853 return TRUE;
857 /**********************************************************************
858 * IsSharedSelector (KERNEL.345)
860 BOOL16 WINAPI IsSharedSelector( HANDLE16 selector )
862 /* Check whether the selector belongs to a DLL */
863 NE_MODULE *pModule = NE_GetPtr( selector );
864 if (!pModule) return FALSE;
865 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;