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