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