No longer directly accessing debuggee memory.
[wine] / loader / ne / segment.c
1 /*
2  * NE segment loading
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995 Alexandre Julliard
6  */
7
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
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 "builtin16.h"
29 #include "debugtools.h"
30 #include "xmalloc.h"
31 #include "toolhelp.h"
32
33 DECLARE_DEBUG_CHANNEL(dll)
34 DECLARE_DEBUG_CHANNEL(fixup)
35 DECLARE_DEBUG_CHANNEL(module)
36 DECLARE_DEBUG_CHANNEL(segment)
37
38 #define SEL(x) ((x)|1)
39
40 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);
41
42 /***********************************************************************
43  *           NE_GetRelocAddrName
44  */
45 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
46 {
47     switch(addr_type & 0x7f)
48     {
49     case NE_RADDR_LOWBYTE:   return additive ? "BYTE add" : "BYTE";
50     case NE_RADDR_OFFSET16:  return additive ? "OFFSET16 add" : "OFFSET16";
51     case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
52     case NE_RADDR_SELECTOR:  return additive ? "SELECTOR add" : "SELECTOR";
53     case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
54     case NE_RADDR_OFFSET32:  return additive ? "OFFSET32 add" : "OFFSET32";
55     }
56     return "???";
57 }
58
59
60 /***********************************************************************
61  *           NE_LoadSegment
62  */
63 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
64 {
65     SEGTABLEENTRY *pSegTable, *pSeg;
66     WORD *pModuleTable;
67     WORD count, i, offset, next_offset;
68     HMODULE16 module;
69     FARPROC16 address = 0;
70     HFILE hf;
71     DWORD res;
72     struct relocation_entry_s *rep, *reloc_entries;
73     BYTE *func_name;
74     int size;
75     char* mem;
76
77     char buffer[256];
78     int ordinal, additive;
79     unsigned short *sp;
80
81     pSegTable = NE_SEG_TABLE( pModule );
82     pSeg = pSegTable + segnum - 1;
83
84     if (pSeg->flags & NE_SEGFLAGS_LOADED)
85     {
86         /* self-loader ? -> already loaded it */
87         if (pModule->flags & NE_FFLAGS_SELFLOAD)
88             return TRUE;
89
90         /* leave, except for DGROUP, as this may be the second instance */
91         if (segnum != pModule->dgroup)
92             return TRUE;
93     }
94
95     if (!pSeg->filepos) return TRUE;  /* No file image, just return */
96         
97     pModuleTable = NE_MODULE_TABLE( pModule );
98
99     hf = NE_OpenFile( pModule );
100     TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
101                     segnum, pSeg->hSeg, pSeg->flags );
102     SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
103     if (pSeg->size) size = pSeg->size;
104     else size = pSeg->minsize ? pSeg->minsize : 0x10000;
105     mem = GlobalLock16(pSeg->hSeg);
106     if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
107     {
108         /* Implement self-loading segments */
109         SELFLOADHEADER *selfloadheader;
110         DWORD oldstack;
111         HFILE hFile32;
112         HFILE16 hFile16;
113
114         selfloadheader = (SELFLOADHEADER *)
115                 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg),0);
116         oldstack = NtCurrentTeb()->cur_stack;
117         NtCurrentTeb()->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
118                                                           0xff00 - sizeof(STACK16FRAME));
119
120         TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
121                 pModule->self,hf,segnum );
122         DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
123                          0, FALSE, DUPLICATE_SAME_ACCESS );
124         hFile16 = FILE_AllocDosHandle( hFile32 );
125         pSeg->hSeg = Callbacks->CallLoadAppSegProc( selfloadheader->LoadAppSeg,
126                                                     pModule->self, hFile16,
127                                                     segnum );
128         TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
129         _lclose16( hFile16 );
130         NtCurrentTeb()->cur_stack = oldstack;
131     }
132     else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
133         ReadFile(hf, mem, size, &res, NULL);
134     else {
135       /*
136          The following bit of code for "iterated segments" was written without
137          any documentation on the format of these segments. It seems to work,
138          but may be missing something. If you have any doc please either send
139          it to me or fix the code yourself. gfm@werple.mira.net.au
140       */
141       char* buff = xmalloc(size);
142       char* curr = buff;
143       ReadFile(hf, buff, size, &res, NULL);
144       while(curr < buff + size) {
145         unsigned int rept = *((short*) curr)++;
146         unsigned int len = *((short*) curr)++;
147         for(; rept > 0; rept--) {
148           char* bytes = curr;
149           unsigned int byte;
150           for(byte = 0; byte < len; byte++)
151             *mem++ = *bytes++;
152         }
153         curr += len;
154       }
155       free(buff);
156     }
157
158     pSeg->flags |= NE_SEGFLAGS_LOADED;
159
160     /* Perform exported function prolog fixups */
161     NE_FixupSegmentPrologs( pModule, segnum );
162
163     if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
164         return TRUE;  /* No relocation data, we are done */
165
166     ReadFile(hf, &count, sizeof(count), &res, NULL);
167     if (!count) return TRUE;
168
169     TRACE_(fixup)("Fixups for %.*s, segment %d, hSeg %04x\n",
170                    *((BYTE *)pModule + pModule->name_table),
171                    (char *)pModule + pModule->name_table + 1,
172                    segnum, pSeg->hSeg );
173     TRACE_(segment)("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
178     reloc_entries = (struct relocation_entry_s *)xmalloc(count * sizeof(struct relocation_entry_s));
179     if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
180         (res != count * sizeof(struct relocation_entry_s)))
181     {
182         WARN_(fixup)("Unable to read relocation information\n" );
183         return FALSE;
184     }
185
186     /*
187      * Go through the relocation table one entry at a time.
188      */
189     rep = reloc_entries;
190     for (i = 0; i < count; i++, rep++)
191     {
192         /*
193          * Get the target address corresponding to this entry.
194          */
195
196         /* If additive, there is no target chain list. Instead, add source
197            and target */
198         additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
199         rep->relocation_type &= 0x3;
200
201         switch (rep->relocation_type)
202         {
203           case NE_RELTYPE_ORDINAL:
204             module = pModuleTable[rep->target1-1];
205             ordinal = rep->target2;
206             address = NE_GetEntryPoint( module, ordinal );
207             if (!address)
208             {
209                 NE_MODULE *pTarget = NE_GetPtr( module );
210                 if (!pTarget)
211                     WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
212                              module, rep->target1, 
213                              *((BYTE *)pModule + pModule->name_table),
214                              *((BYTE *)pModule + pModule->name_table),
215                              (char *)pModule + pModule->name_table + 1 );
216                 else
217                 {
218                     ERR_(fixup)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
219                             *((BYTE *)pTarget + pTarget->name_table),
220                             (char *)pTarget + pTarget->name_table + 1,
221                             ordinal );
222                     address = (FARPROC16)0xdeadbeef;
223                 }
224             }
225             if (TRACE_ON(fixup))
226             {
227                 NE_MODULE *pTarget = NE_GetPtr( module );
228                 TRACE_(fixup)("%d: %.*s.%d=%04x:%04x %s\n", i + 1, 
229                        *((BYTE *)pTarget + pTarget->name_table),
230                        (char *)pTarget + pTarget->name_table + 1,
231                        ordinal, HIWORD(address), LOWORD(address),
232                        NE_GetRelocAddrName( rep->address_type, additive ) );
233             }
234             break;
235             
236           case NE_RELTYPE_NAME:
237             module = pModuleTable[rep->target1-1];
238             func_name = (char *)pModule + pModule->import_table + rep->target2;
239             memcpy( buffer, func_name+1, *func_name );
240             buffer[*func_name] = '\0';
241             func_name = buffer;
242             ordinal = NE_GetOrdinal( module, func_name );
243             address = NE_GetEntryPoint( module, ordinal );
244
245             if (ERR_ON(fixup) && !address)
246             {
247                 NE_MODULE *pTarget = NE_GetPtr( module );
248                 ERR_(fixup)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
249                     *((BYTE *)pTarget + pTarget->name_table),
250                     (char *)pTarget + pTarget->name_table + 1, func_name );
251             }
252             if (!address) address = (FARPROC16) 0xdeadbeef;
253             if (TRACE_ON(fixup))
254             {
255                 NE_MODULE *pTarget = NE_GetPtr( module );
256                 TRACE_(fixup)("%d: %.*s.%s=%04x:%04x %s\n", i + 1, 
257                        *((BYTE *)pTarget + pTarget->name_table),
258                        (char *)pTarget + pTarget->name_table + 1,
259                        func_name, HIWORD(address), LOWORD(address),
260                        NE_GetRelocAddrName( rep->address_type, additive ) );
261             }
262             break;
263             
264           case NE_RELTYPE_INTERNAL:
265             if ((rep->target1 & 0xff) == 0xff)
266             {
267                 address  = NE_GetEntryPoint( pModule->self, rep->target2 );
268             }
269             else
270             {
271                 address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
272             }
273             
274             TRACE_(fixup)("%d: %04x:%04x %s\n", 
275                    i + 1, HIWORD(address), LOWORD(address),
276                    NE_GetRelocAddrName( rep->address_type, additive ) );
277             break;
278
279           case NE_RELTYPE_OSFIXUP:
280             /* Relocation type 7:
281              *
282              *    These appear to be used as fixups for the Windows
283              * floating point emulator.  Let's just ignore them and
284              * try to use the hardware floating point.  Linux should
285              * successfully emulate the coprocessor if it doesn't
286              * exist.
287              */
288             TRACE_(fixup)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
289                    i + 1, rep->relocation_type, rep->offset,
290                    rep->target1, rep->target2,
291                    NE_GetRelocAddrName( rep->address_type, additive ) );
292             continue;
293         }
294
295         offset  = rep->offset;
296
297         /* Apparently, high bit of address_type is sometimes set; */
298         /* we ignore it for now */
299         if (rep->address_type > NE_RADDR_OFFSET32)
300         {
301             char module[10];
302             GetModuleName16( pModule->self, module, sizeof(module) );
303             ERR_(fixup)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
304                  module, rep->address_type );
305         }
306
307         if (additive)
308         {
309             sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
310             TRACE_(fixup)("    %04x:%04x\n", offset, *sp );
311             switch (rep->address_type & 0x7f)
312             {
313             case NE_RADDR_LOWBYTE:
314                 *(BYTE *)sp += LOBYTE((int)address);
315                 break;
316             case NE_RADDR_OFFSET16:
317                 *sp += LOWORD(address);
318                 break;
319             case NE_RADDR_POINTER32:
320                 *sp += LOWORD(address);
321                 *(sp+1) = HIWORD(address);
322                 break;
323             case NE_RADDR_SELECTOR:
324                 /* Borland creates additive records with offset zero. Strange, but OK */
325                 if (*sp)
326                     ERR_(fixup)("Additive selector to %04x.Please report\n",*sp);
327                 else
328                     *sp = HIWORD(address);
329                 break;
330             default:
331                 goto unknown;
332             }
333         }
334         else  /* non-additive fixup */
335         {
336             do
337             {
338                 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
339                 next_offset = *sp;
340                 TRACE_(fixup)("    %04x:%04x\n", offset, *sp );
341                 switch (rep->address_type & 0x7f)
342                 {
343                 case NE_RADDR_LOWBYTE:
344                     *(BYTE *)sp = LOBYTE((int)address);
345                     break;
346                 case NE_RADDR_OFFSET16:
347                     *sp = LOWORD(address);
348                     break;
349                 case NE_RADDR_POINTER32:
350                     *(FARPROC16 *)sp = address;
351                     break;
352                 case NE_RADDR_SELECTOR:
353                     *sp = SELECTOROF(address);
354                     break;
355                 default:
356                     goto unknown;
357                 }
358                 if (next_offset == offset) break;  /* avoid infinite loop */
359                 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
360                 offset = next_offset;
361             } while (offset != 0xffff);
362         }
363     }
364
365     free(reloc_entries);
366     return TRUE;
367
368 unknown:
369     WARN_(fixup)("WARNING: %d: unknown ADDR TYPE %d,  "
370          "TYPE %d,  OFFSET %04x,  TARGET %04x %04x\n",
371          i + 1, rep->address_type, rep->relocation_type, 
372          rep->offset, rep->target1, rep->target2);
373     free(reloc_entries);
374     return FALSE;
375 }
376
377
378 /***********************************************************************
379  *           NE_LoadAllSegments
380  */
381 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
382 {
383     int i;
384     SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
385
386     if (pModule->flags & NE_FFLAGS_SELFLOAD)
387     {
388         HFILE hf;
389         HFILE16 hFile16;
390         /* Handle self-loading modules */
391         SELFLOADHEADER *selfloadheader;
392         HMODULE16 hselfload = GetModuleHandle16("WPROCS");
393         DWORD oldstack;
394
395         TRACE_(module)("%.*s is a self-loading module!\n",
396                      *((BYTE*)pModule + pModule->name_table),
397                      (char *)pModule + pModule->name_table + 1);
398         if (!NE_LoadSegment( pModule, 1 )) return FALSE;
399         selfloadheader = (SELFLOADHEADER *)
400                           PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg), 0);
401         selfloadheader->EntryAddrProc = NE_GetEntryPoint(hselfload,27);
402         selfloadheader->MyAlloc  = NE_GetEntryPoint(hselfload,28);
403         selfloadheader->SetOwner = NE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
404         pModule->self_loading_sel = SEL(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
405         oldstack = NtCurrentTeb()->cur_stack;
406         NtCurrentTeb()->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
407                                                           0xff00 - sizeof(STACK16FRAME) );
408
409         DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule),
410                          GetCurrentProcess(), &hf, 0, FALSE, DUPLICATE_SAME_ACCESS );
411         hFile16 = FILE_AllocDosHandle( hf );
412         TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
413               pModule->self,hFile16);
414         Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self,hFile16);
415         TRACE_(dll)("Return from CallBootAppProc\n");
416         _lclose16(hf);
417         NtCurrentTeb()->cur_stack = oldstack;
418
419         for (i = 2; i <= pModule->seg_count; i++)
420             if (!NE_LoadSegment( pModule, i )) return FALSE;
421     }
422     else
423     {
424         for (i = 1; i <= pModule->seg_count; i++)
425             if (!NE_LoadSegment( pModule, i )) return FALSE;
426     }
427     return TRUE;
428 }
429
430
431 /***********************************************************************
432  *           NE_FixupSegmentPrologs
433  *
434  * Fixup exported functions prologs of one segment
435  */
436 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
437 {
438     SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
439     ET_BUNDLE *bundle;
440     ET_ENTRY *entry;
441     WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
442     BYTE *pSeg, *pFunc;
443
444     TRACE_(module)("(%d);\n", segnum);
445
446     if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
447     {
448         pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
449         return;
450     }
451
452     if (!pModule->dgroup) return;
453
454     if (!(dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg))) return;
455     
456     pSeg = PTR_SEG_OFF_TO_LIN(sel, 0);
457
458     bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);
459
460     do {
461         TRACE_(module)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
462         if (!(num_entries = bundle->last - bundle->first))
463             return;
464         entry = (ET_ENTRY *)((BYTE *)bundle+6);
465         while (num_entries--)
466     {
467             /*TRACE(module, "entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
468             if (entry->segnum == segnum)
469         {
470                 pFunc = ((BYTE *)pSeg+entry->offs);
471                 TRACE_(module)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
472                 if (*(pFunc+2) == 0x90)
473         {
474                     if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
475                     {
476                         TRACE_(module)("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
477                         *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
478         }
479
480                     if (*(WORD *)pFunc == 0xd88c)
481                         {
482                         if ((entry->flags & 2)) /* public data ? */
483                         {
484                             TRACE_(module)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
485                             *pFunc = 0xb8; /* mov ax, */
486                             *(WORD *)(pFunc+1) = dgroup;
487                     }
488                     else
489                         if ((pModule->flags & NE_FFLAGS_MULTIPLEDATA)
490                         && (entry->flags & 1)) /* exported ? */
491                     {
492                             TRACE_(module)("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
493                             *(WORD *)pFunc = 0x9090; /* nop, nop */
494                         }
495                     }
496                 }
497             }
498             entry++;
499         }
500     } while ( (bundle->next)
501          && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
502 }
503
504
505 /***********************************************************************
506  *           PatchCodeHandle
507  *
508  * Needed for self-loading modules.
509  */
510 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
511 {
512     WORD segnum;
513     WORD sel = SEL(hSeg);
514     NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
515     SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
516
517     TRACE_(module)("(%04x);\n", hSeg);
518
519     /* find the segment number of the module that belongs to hSeg */
520     for (segnum = 1; segnum <= pModule->seg_count; segnum++)
521     {
522         if (SEL(pSegTable[segnum-1].hSeg) == sel)
523         {
524             NE_FixupSegmentPrologs(pModule, segnum);
525             break;
526         }
527     }
528
529     return MAKELONG(hSeg, sel);
530 }
531
532
533 /***********************************************************************
534  *           NE_GetDLLInitParams
535  */
536 static VOID NE_GetDLLInitParams( NE_MODULE *pModule, 
537                                  WORD *hInst, WORD *ds, WORD *heap )
538 {
539     SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
540
541     if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
542     {
543         if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
544         {
545             /* Not SINGLEDATA */
546             ERR_(dll)("Library is not marked SINGLEDATA\n");
547             exit(1);
548         }
549         else  /* DATA NONE DLL */
550         {
551             *ds = 0;
552             *heap = 0;
553         }
554     }
555     else  /* DATA SINGLE DLL */
556     {
557         if (pModule->dgroup) {
558             *ds   = SEL(pSegTable[pModule->dgroup-1].hSeg);
559             *heap = pModule->heap_size;
560         }
561         else /* hmm, DLL has no dgroup,
562                 but why has it NE_FFLAGS_SINGLEDATA set ?
563                 Buggy DLL compiler ? */
564         {
565             *ds   = 0;
566             *heap = 0;
567         }
568     }
569
570     *hInst = *ds ? *ds : pModule->self;
571 }
572
573
574 /***********************************************************************
575  *           NE_InitDLL
576  *
577  * Call the DLL initialization code
578  */
579 static BOOL NE_InitDLL( TDB* pTask, NE_MODULE *pModule )
580 {
581     SEGTABLEENTRY *pSegTable;
582     WORD hInst, ds, heap;
583     CONTEXT86 context;
584
585     pSegTable = NE_SEG_TABLE( pModule );
586
587     if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
588         (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
589
590     /* Call USER signal handler for Win3.1 compatibility. */
591     TASK_CallTaskSignalProc( USIG16_DLL_LOAD, pModule->self );
592
593     if (!pModule->cs) return TRUE;  /* no initialization code */
594
595
596     /* Registers at initialization must be:
597      * cx     heap size
598      * di     library instance
599      * ds     data segment if any
600      * es:si  command line (always 0)
601      */
602
603     memset( &context, 0, sizeof(context) );
604
605     NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
606
607     ECX_reg(&context) = heap;
608     EDI_reg(&context) = hInst;
609     DS_reg(&context)  = ds;
610     ES_reg(&context)  = ds;   /* who knows ... */
611
612     CS_reg(&context)  = SEL(pSegTable[pModule->cs-1].hSeg);
613     EIP_reg(&context) = pModule->ip;
614     EBP_reg(&context) = OFFSETOF(NtCurrentTeb()->cur_stack) + (WORD)&((STACK16FRAME*)0)->bp;
615
616
617     pModule->cs = 0;  /* Don't initialize it twice */
618     TRACE_(dll)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n", 
619                  CS_reg(&context), EIP_reg(&context), DS_reg(&context),
620                  DI_reg(&context), CX_reg(&context) );
621     Callbacks->CallRegisterShortProc( &context, 0 );
622     return TRUE;
623 }
624
625 /***********************************************************************
626  *           NE_InitializeDLLs
627  *
628  * Recursively initialize all DLLs (according to the order in which 
629  * they where loaded).
630  */
631 void NE_InitializeDLLs( HMODULE16 hModule )
632 {
633     TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
634     NE_MODULE *pModule;
635     HMODULE16 *pDLL;
636
637     if (!(pModule = NE_GetPtr( hModule ))) return;
638     assert( !(pModule->flags & NE_FFLAGS_WIN32) );
639
640     if (pModule->dlls_to_init)
641     {
642         HGLOBAL16 to_init = pModule->dlls_to_init;
643         pModule->dlls_to_init = 0;
644         for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
645         {
646             NE_InitializeDLLs( *pDLL );
647         }
648         GlobalFree16( to_init );
649     }
650     NE_InitDLL( pTask, pModule );
651 }
652
653
654 /***********************************************************************
655  *           NE_CallDllEntryPoint
656  *
657  * Call the DllEntryPoint of DLLs with subsystem >= 4.0 
658  */
659 typedef DWORD WINAPI (*WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
660
661 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
662 {
663     WORD hInst, ds, heap;
664     FARPROC16 entryPoint;
665     WORD ordinal;
666
667     if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) return;
668     if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
669     if (!(ordinal = NE_GetOrdinal( pModule->self, "DllEntryPoint" ))) return;
670     if (!(entryPoint = NE_GetEntryPoint( pModule->self, ordinal ))) return;
671
672     NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
673
674     TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
675                  NE_MODULE_NAME( pModule ),
676                  SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
677
678     if ( pModule->flags & NE_FFLAGS_BUILTIN )
679     {
680         WinNEEntryProc entryProc = (WinNEEntryProc)
681                           ((ENTRYPOINT16 *)PTR_SEG_TO_LIN( entryPoint ))->target;
682
683         entryProc( dwReason, hInst, ds, heap, 0, 0 );
684     }
685     else
686     {
687         LPBYTE stack = (LPBYTE)CURRENT_STACK16;
688         CONTEXT86 context;
689
690         memset( &context, 0, sizeof(context) );
691         DS_reg(&context) = ds;
692         ES_reg(&context) = ds;   /* who knows ... */
693
694         CS_reg(&context) = HIWORD(entryPoint);
695         EIP_reg(&context) = LOWORD(entryPoint);
696         EBP_reg(&context) =  OFFSETOF( NtCurrentTeb()->cur_stack )
697                              + (WORD)&((STACK16FRAME*)0)->bp;
698
699         *(DWORD *)(stack -  4) = dwReason;      /* dwReason */
700         *(WORD *) (stack -  6) = hInst;         /* hInst */
701         *(WORD *) (stack -  8) = ds;            /* wDS */
702         *(WORD *) (stack - 10) = heap;          /* wHeapSize */
703         *(DWORD *)(stack - 14) = 0;             /* dwReserved1 */
704         *(WORD *) (stack - 16) = 0;             /* wReserved2 */
705
706         Callbacks->CallRegisterShortProc( &context, 16 );
707     }
708 }
709
710 /***********************************************************************
711  *           NE_DllProcessAttach
712  * 
713  * Call the DllEntryPoint of all modules this one (recursively)
714  * depends on, according to the order in which they were loaded.
715  *
716  * Note that --as opposed to the PE module case-- there is no notion
717  * of 'module loaded into a process' for NE modules, and hence we 
718  * have no place to store the fact that the DllEntryPoint of a
719  * given module was already called on behalf of this process (e.g.
720  * due to some earlier LoadLibrary16 call).
721  *
722  * Thus, we just call the DllEntryPoint twice in that case.  Win9x
723  * appears to behave this way as well ...
724  *
725  * This routine must only be called with the Win16Lock held.
726  * 
727  * FIXME:  We should actually abort loading in case the DllEntryPoint
728  *         returns FALSE ...
729  *
730  */
731 void NE_DllProcessAttach( HMODULE16 hModule )
732 {
733     NE_MODULE *pModule;
734     WORD *pModRef;
735     int i;
736
737     if (!(pModule = NE_GetPtr( hModule ))) return;
738     assert( !(pModule->flags & NE_FFLAGS_WIN32) );
739
740     /* Check for recursive call */
741     if ( pModule->misc_flags & 0x80 ) return;
742
743     TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
744
745     /* Tag current module to prevent recursive loop */
746     pModule->misc_flags |= 0x80;
747
748     /* Recursively attach all DLLs this one depends on */
749     pModRef = NE_MODULE_TABLE( pModule );
750     for ( i = 0; i < pModule->modref_count; i++ )
751         if ( pModRef[i] )
752             NE_DllProcessAttach( (HMODULE16)pModRef[i] );
753
754     /* Call DLL entry point */
755     NE_CallDllEntryPoint( pModule, DLL_PROCESS_ATTACH );
756
757     /* Remove recursion flag */
758     pModule->misc_flags &= ~0x80;
759
760     TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
761 }
762
763
764 /***********************************************************************
765  *           NE_Ne2MemFlags
766  *
767  * This function translates NE segment flags to GlobalAlloc flags
768  */
769 static WORD NE_Ne2MemFlags(WORD flags)
770
771     WORD memflags = 0;
772 #if 1
773     if (flags & NE_SEGFLAGS_DISCARDABLE) 
774       memflags |= GMEM_DISCARDABLE;
775     if (flags & NE_SEGFLAGS_MOVEABLE || 
776         ( ! (flags & NE_SEGFLAGS_DATA) &&
777           ! (flags & NE_SEGFLAGS_LOADED) &&
778           ! (flags & NE_SEGFLAGS_ALLOCATED)
779          )
780         )
781       memflags |= GMEM_MOVEABLE;
782     memflags |= GMEM_ZEROINIT;
783 #else
784     memflags = GMEM_ZEROINIT | GMEM_FIXED;
785 #endif
786     return memflags;
787 }
788
789 /***********************************************************************
790  *           NE_AllocateSegment (WPROCS.26)
791  *
792  * MyAlloc() function for self-loading apps.
793  */
794 DWORD WINAPI NE_AllocateSegment( WORD wFlags, WORD wSize, WORD wElem )
795 {
796     WORD size = wSize << wElem;
797     HANDLE16 hMem = 0;
798
799     if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
800         hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
801
802     if ( ((wFlags & 0x7) != 0x1) && /* DATA */
803          ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
804     {
805         WORD hSel = SEL(hMem);
806         WORD access = SelectorAccessRights16(hSel,0,0);
807
808         access |= 2<<2; /* SEGMENT_CODE */
809         SelectorAccessRights16(hSel,1,access);
810     }
811     if (size)
812         return MAKELONG( hMem, SEL(hMem) );
813     else
814         return MAKELONG( 0, hMem );
815 }
816
817 /***********************************************************************
818  *           NE_GetInstance
819  */
820 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
821 {
822     if ( !pModule->dgroup )
823         return pModule->self;
824     else
825     {
826         SEGTABLEENTRY *pSeg;
827         pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
828
829         return SEL(pSeg->hSeg);
830     }
831 }    
832
833 /***********************************************************************
834  *           NE_CreateSegment
835  */
836 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
837 {
838     SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
839     int minsize;
840
841     assert( !(pModule->flags & NE_FFLAGS_WIN32) );
842
843     if ( segnum < 1 || segnum > pModule->seg_count )
844         return FALSE;
845
846     if ( (pModule->flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
847         return TRUE;    /* selfloader allocates segment itself */
848
849     if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->dgroup )
850         return TRUE;    /* all but DGROUP only allocated once */
851
852     minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
853     if ( segnum == pModule->ss )     minsize += pModule->stack_size;
854     if ( segnum == pModule->dgroup ) minsize += pModule->heap_size;
855
856     pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags),
857                                    minsize, pModule->self,
858                                    !(pSeg->flags & NE_SEGFLAGS_DATA),
859                                     (pSeg->flags & NE_SEGFLAGS_32BIT) != 0,
860                             FALSE /*pSeg->flags & NE_SEGFLAGS_READONLY*/ );
861     if (!pSeg->hSeg) return FALSE;
862
863     pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
864     return TRUE;
865 }
866
867 /***********************************************************************
868  *           NE_CreateAllSegments
869  */
870 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
871 {
872     int i;
873     for ( i = 1; i <= pModule->seg_count; i++ )
874         if ( !NE_CreateSegment( pModule, i ) )
875             return FALSE;
876
877     pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
878                             (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
879     return TRUE;
880 }
881
882
883 /**********************************************************************
884  *          IsSharedSelector    (KERNEL.345)
885  */
886 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
887 {
888     /* Check whether the selector belongs to a DLL */
889     NE_MODULE *pModule = NE_GetPtr( selector );
890     if (!pModule) return FALSE;
891     return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;
892 }