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