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