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