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