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