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