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