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