Release 971221
[wine] / loader / ne_image.c
1 /*
2  * NE modules
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995 Alexandre Julliard
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <ctype.h>
15 #include <string.h>
16 #include <errno.h>
17 #include "neexe.h"
18 #include "windows.h"
19 #include "global.h"
20 #include "task.h"
21 #include "selectors.h"
22 #include "callback.h"
23 #include "file.h"
24 #include "module.h"
25 #include "stackframe.h"
26 #include "stddebug.h"
27 #include "debug.h"
28 #include "xmalloc.h"
29
30
31 /***********************************************************************
32  *           NE_LoadSegment
33  */
34 BOOL32 NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
35 {
36     SEGTABLEENTRY *pSegTable, *pSeg;
37     WORD *pModuleTable;
38     WORD count, i, offset;
39     HMODULE16 module;
40     FARPROC16 address;
41     int fd;
42     struct relocation_entry_s *rep, *reloc_entries;
43     BYTE *func_name;
44     int size;
45     char* mem;
46
47     char buffer[256];
48     int ordinal, additive;
49     unsigned short *sp;
50
51     pSegTable = NE_SEG_TABLE( pModule );
52     pSeg = pSegTable + segnum - 1;
53     pModuleTable = NE_MODULE_TABLE( pModule );
54
55     if (!pSeg->filepos) return TRUE;  /* No file image, just return */
56         
57     fd = MODULE_OpenFile( pModule->self );
58     dprintf_module( stddeb, "Loading segment %d, selector=%04x, flags=%04x\n",
59                     segnum, pSeg->selector, pSeg->flags );
60     lseek( fd, pSeg->filepos << pModule->alignment, SEEK_SET );
61     if (pSeg->size) size = pSeg->size;
62     else if (pSeg->minsize) size = pSeg->minsize;
63     else size = 0x10000;
64     mem = GlobalLock16(pSeg->selector);
65     if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
66     {
67         /* Implement self loading segments */
68         SELFLOADHEADER *selfloadheader;
69         STACK16FRAME *stack16Top;
70         DWORD oldstack;
71         WORD oldselector, newselector;
72         HFILE32 hf = FILE_DupUnixHandle( fd );
73
74         selfloadheader = (SELFLOADHEADER *)
75                 PTR_SEG_OFF_TO_LIN(pSegTable->selector,0);
76         oldstack = IF1632_Saved16_ss_sp;
77         oldselector = pSeg->selector;
78         IF1632_Saved16_ss_sp = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
79                                                  0xff00 - sizeof(*stack16Top));
80         stack16Top = CURRENT_STACK16;
81         stack16Top->saved_ss_sp = 0;
82         stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
83         stack16Top->entry_point = 0;
84         stack16Top->entry_ip = 0;
85         stack16Top->entry_cs = 0;
86         stack16Top->bp = 0;
87         stack16Top->ip = 0;
88         stack16Top->cs = 0;
89         newselector = Callbacks->CallLoadAppSegProc(selfloadheader->LoadAppSeg,
90                                                    pModule->self, hf, segnum );
91         _lclose32( hf );
92         if (newselector != oldselector) {
93           /* Self loaders like creating their own selectors; 
94            * they love asking for trouble to Wine developers
95            */
96           if (segnum == pModule->dgroup) {
97             memcpy(PTR_SEG_OFF_TO_LIN(oldselector,0),
98                    PTR_SEG_OFF_TO_LIN(newselector,0), 
99                    pSeg->minsize ? pSeg->minsize : 0x10000);
100             FreeSelector(newselector);
101             pSeg->selector = oldselector;
102             fprintf(stderr, "A new selector was allocated for the dgroup segment\n"
103                     "Old selector is %d, new one is %d", oldselector, newselector);
104           } else {
105             FreeSelector(pSeg->selector);
106             pSeg->selector = newselector;
107           }
108         } 
109         
110         IF1632_Saved16_ss_sp = oldstack;
111     }
112     else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
113       read(fd, mem, size);
114     else {
115       /*
116          The following bit of code for "iterated segments" was written without
117          any documentation on the format of these segments. It seems to work,
118          but may be missing something. If you have any doco please either send
119          it to me or fix the code yourself. gfm@werple.mira.net.au
120       */
121       char* buff = xmalloc(size);
122       char* curr = buff;
123       read(fd, buff, size);
124       while(curr < buff + size) {
125         unsigned int rept = *((short*) curr)++;
126         unsigned int len = *((short*) curr)++;
127         for(; rept > 0; rept--) {
128           char* bytes = curr;
129           unsigned int byte;
130           for(byte = 0; byte < len; byte++)
131             *mem++ = *bytes++;
132         }
133         curr += len;
134       }
135       free(buff);
136     }
137
138     pSeg->flags |= NE_SEGFLAGS_LOADED;
139     if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
140         return TRUE;  /* No relocation data, we are done */
141
142     read( fd, &count, sizeof(count) );
143     if (!count) return TRUE;
144
145     dprintf_fixup( stddeb, "Fixups for %*.*s, segment %d, selector %04x\n",
146                    *((BYTE *)pModule + pModule->name_table),
147                    *((BYTE *)pModule + pModule->name_table),
148                    (char *)pModule + pModule->name_table + 1,
149                    segnum, pSeg->selector );
150
151     reloc_entries = (struct relocation_entry_s *)xmalloc(count * sizeof(struct relocation_entry_s));
152     if (read( fd, reloc_entries, count * sizeof(struct relocation_entry_s)) !=
153             count * sizeof(struct relocation_entry_s))
154     {
155         dprintf_fixup( stddeb, "Unable to read relocation information\n" );
156         return FALSE;
157     }
158
159     /*
160      * Go through the relocation table on entry at a time.
161      */
162     rep = reloc_entries;
163     for (i = 0; i < count; i++, rep++)
164     {
165         /*
166          * Get the target address corresponding to this entry.
167          */
168
169         /* If additive, there is no target chain list. Instead, add source
170            and target */
171         additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
172         rep->relocation_type &= 0x3;
173         
174         switch (rep->relocation_type)
175         {
176           case NE_RELTYPE_ORDINAL:
177             module = pModuleTable[rep->target1-1];
178             ordinal = rep->target2;
179             address = MODULE_GetEntryPoint( module, ordinal );
180             if (!address)
181             {
182                 NE_MODULE *pTarget = MODULE_GetPtr( module );
183                 if (!pTarget)
184                     fprintf( stderr, "Module not found: %04x, reference %d of module %*.*s\n",
185                              module, rep->target1, 
186                              *((BYTE *)pModule + pModule->name_table),
187                              *((BYTE *)pModule + pModule->name_table),
188                              (char *)pModule + pModule->name_table + 1 );
189                 else
190                     fprintf( stderr, "Warning: no handler for %*.*s.%d, setting to 0:0\n",
191                             *((BYTE *)pTarget + pTarget->name_table),
192                             *((BYTE *)pTarget + pTarget->name_table),
193                             (char *)pTarget + pTarget->name_table + 1,
194                             ordinal );
195             }
196             if (debugging_fixup)
197             {
198                 NE_MODULE *pTarget = MODULE_GetPtr( module );
199                 fprintf( stddeb,"%d: %*.*s.%d=%04x:%04x\n", i + 1, 
200                          *((BYTE *)pTarget + pTarget->name_table),
201                          *((BYTE *)pTarget + pTarget->name_table),
202                          (char *)pTarget + pTarget->name_table + 1,
203                          ordinal, HIWORD(address), LOWORD(address) );
204             }
205             break;
206             
207           case NE_RELTYPE_NAME:
208             module = pModuleTable[rep->target1-1];
209             func_name = (char *)pModule + pModule->import_table + rep->target2;
210             memcpy( buffer, func_name+1, *func_name );
211             buffer[*func_name] = '\0';
212             func_name = buffer;
213             ordinal = MODULE_GetOrdinal( module, func_name );
214
215             address = MODULE_GetEntryPoint( module, ordinal );
216
217             if (!address)
218             {
219                 NE_MODULE *pTarget = MODULE_GetPtr( module );
220                 fprintf( stderr, "Warning: no handler for %.*s.%s, setting to 0:0\n",
221                         *((BYTE *)pTarget + pTarget->name_table),
222                         (char *)pTarget + pTarget->name_table + 1, func_name );
223             }
224             if (debugging_fixup)
225             {
226                 NE_MODULE *pTarget = MODULE_GetPtr( module );
227                 fprintf( stddeb,"%d: %.*s.%s=%04x:%04x\n", i + 1, 
228                          *((BYTE *)pTarget + pTarget->name_table),
229                          (char *)pTarget + pTarget->name_table + 1,
230                          func_name, HIWORD(address), LOWORD(address) );
231             }
232             break;
233             
234           case NE_RELTYPE_INTERNAL:
235             if ((rep->target1 & 0xff) == 0xff)
236             {
237                 address  = MODULE_GetEntryPoint( pModule->self, rep->target2 );
238             }
239             else
240             {
241                 address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( pSegTable[rep->target1-1].selector, rep->target2 );
242             }
243             
244             dprintf_fixup(stddeb,"%d: %04x:%04x\n", 
245                           i + 1, HIWORD(address), LOWORD(address) );
246             break;
247
248           case NE_RELTYPE_OSFIXUP:
249             /* Relocation type 7:
250              *
251              *    These appear to be used as fixups for the Windows
252              * floating point emulator.  Let's just ignore them and
253              * try to use the hardware floating point.  Linux should
254              * successfully emulate the coprocessor if it doesn't
255              * exist.
256              */
257             dprintf_fixup(stddeb,
258                    "%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04x,  ",
259                    i + 1, rep->address_type, rep->relocation_type, 
260                    rep->offset);
261             dprintf_fixup(stddeb,"TARGET %04x %04x\n", 
262                    rep->target1, rep->target2);
263             continue;
264             
265           default:
266             dprintf_fixup(stddeb,
267                    "WARNING: %d: ADDR TYPE %d,  unknown TYPE %d,  OFFSET %04x,  ",
268                    i + 1, rep->address_type, rep->relocation_type, 
269                    rep->offset);
270             dprintf_fixup(stddeb,"TARGET %04x %04x\n", 
271                     rep->target1, rep->target2);
272             free(reloc_entries);
273             return FALSE;
274         }
275
276         offset  = rep->offset;
277
278         /* Apparently, high bit of address_type is sometimes set; */
279         /* we ignore it for now */
280         if (rep->address_type > NE_RADDR_OFFSET32)
281             fprintf( stderr, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
282                      MODULE_GetModuleName(pModule->self), rep->address_type );
283
284         switch (rep->address_type & 0x7f)
285         {
286           case NE_RADDR_LOWBYTE:
287             do {
288                 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
289                 dprintf_fixup(stddeb,"    %04x:%04x:%04x BYTE%s\n",
290                               pSeg->selector, offset, *sp, additive ? " additive":"");
291                 offset = *sp;
292                 if(additive)
293                     *(unsigned char*)sp = (unsigned char)(((int)address+offset) & 0xFF);
294                 else
295                     *(unsigned char*)sp = (unsigned char)((int)address & 0xFF);
296             }
297             while (offset != 0xffff && !additive);
298             break;
299
300           case NE_RADDR_OFFSET16:
301             do {
302                 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
303                 dprintf_fixup(stddeb,"    %04x:%04x:%04x OFFSET16%s\n",
304                               pSeg->selector, offset, *sp, additive ? " additive" : "" );
305                 offset = *sp;
306                 *sp = LOWORD(address);
307                 if (additive) *sp += offset;
308             } 
309             while (offset != 0xffff && !additive);
310             break;
311             
312           case NE_RADDR_POINTER32:
313             do {
314                 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
315                 dprintf_fixup(stddeb,"    %04x:%04x:%04x POINTER32%s\n",
316                               pSeg->selector, offset, *sp, additive ? " additive" : "" );
317                 offset = *sp;
318                 *sp    = LOWORD(address);
319                 if (additive) *sp += offset;
320                 *(sp+1) = HIWORD(address);
321             } 
322             while (offset != 0xffff && !additive);
323             break;
324             
325           case NE_RADDR_SELECTOR:
326             do {
327                 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
328                 dprintf_fixup(stddeb,"    %04x:%04x:%04x SELECTOR%s\n",
329                               pSeg->selector, offset, *sp, additive ? " additive" : "" );
330                 offset = *sp;
331                 *sp    = HIWORD(address);
332                 /* Borland creates additive records with offset zero. Strange, but OK */
333                 if(additive && offset)
334                 fprintf(stderr,"Additive selector to %4.4x.Please report\n",offset);
335             } 
336             /* FIXME: Quicken 5 has a zero offset fixup.  This seems to work */
337             while (offset && offset != 0xffff && !additive);
338             break;
339             
340           default:
341             dprintf_fixup(stddeb,
342                    "WARNING: %d: unknown ADDR TYPE %d,  TYPE %d,  OFFSET %04x,  ",
343                    i + 1, rep->address_type, rep->relocation_type, 
344                    rep->offset);
345             dprintf_fixup(stddeb,
346                    "TARGET %04x %04x\n", rep->target1, rep->target2);
347             free(reloc_entries);
348             return FALSE;
349         }
350     }
351
352     free(reloc_entries);
353     return TRUE;
354 }
355
356
357 /***********************************************************************
358  *           NE_LoadAllSegments
359  */
360 BOOL32 NE_LoadAllSegments( NE_MODULE *pModule )
361 {
362     int i;
363
364     if (pModule->flags & NE_FFLAGS_SELFLOAD)
365     {
366         HFILE32 hf;
367         /* Handle self loading modules */
368         SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
369         SELFLOADHEADER *selfloadheader;
370         STACK16FRAME *stack16Top;
371         HMODULE16 hselfload = GetModuleHandle16("WPROCS");
372         DWORD oldstack;
373         WORD saved_dgroup = pSegTable[pModule->dgroup - 1].selector;
374
375         dprintf_module(stddeb, "MODULE_Load: %.*s is a self-loading module!\n",
376                        *((BYTE*)pModule + pModule->name_table),
377                        (char *)pModule + pModule->name_table + 1);
378         if (!NE_LoadSegment( pModule, 1 )) return FALSE;
379         selfloadheader = (SELFLOADHEADER *)
380                           PTR_SEG_OFF_TO_LIN(pSegTable->selector, 0);
381         selfloadheader->EntryAddrProc = MODULE_GetEntryPoint(hselfload,27);
382         selfloadheader->MyAlloc  = MODULE_GetEntryPoint(hselfload,28);
383         selfloadheader->SetOwner = MODULE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
384         pModule->self_loading_sel = GlobalHandleToSel(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
385         oldstack = IF1632_Saved16_ss_sp;
386         IF1632_Saved16_ss_sp = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
387                                                 0xff00 - sizeof(*stack16Top) );
388         stack16Top = CURRENT_STACK16;
389         stack16Top->saved_ss_sp = 0;
390         stack16Top->ebp = 0;
391         stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
392         stack16Top->entry_point = 0;
393         stack16Top->entry_ip = 0;
394         stack16Top->entry_cs = 0;
395         stack16Top->bp = 0;
396         stack16Top->ip = 0;
397         stack16Top->cs = 0;
398
399         hf = FILE_DupUnixHandle( MODULE_OpenFile( pModule->self ) );
400         Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self, hf);
401         _lclose32(hf);
402         /* some BootApp procs overwrite the selector of dgroup */
403         pSegTable[pModule->dgroup - 1].selector = saved_dgroup;
404         IF1632_Saved16_ss_sp = oldstack;
405         for (i = 2; i <= pModule->seg_count; i++)
406             if (!NE_LoadSegment( pModule, i )) return FALSE;
407     }
408     else
409     {
410         for (i = 1; i <= pModule->seg_count; i++)
411             if (!NE_LoadSegment( pModule, i )) return FALSE;
412     }
413     return TRUE;
414 }
415
416
417 /***********************************************************************
418  *           NE_LoadDLLs
419  */
420 BOOL32 NE_LoadDLLs( NE_MODULE *pModule )
421 {
422     int i;
423     WORD *pModRef = (WORD *)((char *)pModule + pModule->modref_table);
424     WORD *pDLLs = (WORD *)GlobalLock16( pModule->dlls_to_init );
425
426     for (i = 0; i < pModule->modref_count; i++, pModRef++)
427     {
428         char buffer[256];
429         BYTE *pstr = (BYTE *)pModule + pModule->import_table + *pModRef;
430         memcpy( buffer, pstr + 1, *pstr );
431         strcpy( buffer + *pstr, ".dll" );
432         dprintf_module( stddeb, "Loading '%s'\n", buffer );
433         if (!(*pModRef = MODULE_FindModule( buffer )))
434         {
435             /* If the DLL is not loaded yet, load it and store */
436             /* its handle in the list of DLLs to initialize.   */
437             HMODULE16 hDLL;
438
439             if ((hDLL = MODULE_Load( buffer, (LPVOID)-1, NE_FFLAGS_IMPLICIT )) == 2)
440             {
441                 /* file not found */
442                 char *p;
443
444                 /* Try with prepending the path of the current module */
445                 GetModuleFileName16( pModule->self, buffer, sizeof(buffer) );
446                 if (!(p = strrchr( buffer, '\\' ))) p = buffer;
447                 memcpy( p + 1, pstr + 1, *pstr );
448                 strcpy( p + 1 + *pstr, ".dll" );
449                 hDLL = MODULE_Load( buffer, (LPVOID)-1, NE_FFLAGS_IMPLICIT );
450             }
451             if (hDLL < 32)
452             {
453                 /* FIXME: cleanup what was done */
454
455                 fprintf( stderr, "Could not load '%s' required by '%.*s', error = %d\n",
456                          buffer, *((BYTE*)pModule + pModule->name_table),
457                          (char *)pModule + pModule->name_table + 1, hDLL );
458                 return FALSE;
459             }
460             *pModRef = MODULE_HANDLEtoHMODULE16( hDLL );
461             *pDLLs++ = *pModRef;
462         }
463         else  /* Increment the reference count of the DLL */
464         {
465             NE_MODULE *pOldDLL = MODULE_GetPtr( *pModRef );
466             if (pOldDLL) pOldDLL->count++;
467         }
468     }
469     return TRUE;
470 }
471
472
473 /***********************************************************************
474  *           NE_FixupPrologs
475  *
476  * Fixup the exported functions prologs.
477  */
478 void NE_FixupPrologs( NE_MODULE *pModule )
479 {
480     SEGTABLEENTRY *pSegTable;
481     WORD dgroup = 0;
482     WORD sel;
483     BYTE *p, *fixup_ptr, count;
484
485     pSegTable = NE_SEG_TABLE(pModule);
486     if (pModule->flags & NE_FFLAGS_SINGLEDATA)
487         dgroup = pSegTable[pModule->dgroup-1].selector;
488
489     dprintf_module( stddeb, "MODULE_FixupPrologs(%04x)\n", pModule->self );
490     p = (BYTE *)pModule + pModule->entry_table;
491     while (*p)
492     {
493         if (p[1] == 0)  /* Unused entry */
494         {
495             p += 2;  /* Skip it */
496             continue;
497         }
498         if (p[1] == 0xfe)  /* Constant entry */
499         {
500             p += 2 + *p * 3;  /* Skip it */
501             continue;
502         }
503
504         /* Now fixup the entries of this bundle */
505         count = *p;
506         sel = p[1];
507         p += 2;
508         while (count-- > 0)
509         {
510             dprintf_module( stddeb,"Flags: %04x, sel %02x ", *p, sel);
511             /* According to the output generated by TDUMP, the flags mean:
512              * 0x0001 function is exported
513              * 0x0002 Single data (seems to occur only in DLLs)
514              */
515             if (sel == 0xff) { /* moveable */
516                 dprintf_module( stddeb, "(%02x) o %04x ", p[3], *(WORD *)(p+4) );
517                 fixup_ptr = (char *)GET_SEL_BASE(pSegTable[p[3]-1].selector) + *(WORD *)(p + 4);
518             } else { /* fixed */
519                 dprintf_module( stddeb, "offset %04x ", *(WORD *)(p+1) );
520                 fixup_ptr = (char *)GET_SEL_BASE(pSegTable[sel-1].selector) + *(WORD *)(p + 1);
521             }
522             dprintf_module( stddeb, "Signature: %02x %02x %02x,ff %x\n",
523                            fixup_ptr[0], fixup_ptr[1], fixup_ptr[2],
524                            pModule->flags );
525             if (*p & 0x0001)
526             {
527                 /* Verify the signature */
528                 if (((fixup_ptr[0] == 0x1e && fixup_ptr[1] == 0x58)
529                      || (fixup_ptr[0] == 0x8c && fixup_ptr[1] == 0xd8))
530                     && fixup_ptr[2] == 0x90)
531                 {
532                     if (*p & 0x0002)
533                     {
534                         if (pModule->flags & NE_FFLAGS_MULTIPLEDATA)
535                         {
536                             /* can this happen? */
537                             fprintf( stderr, "FixupPrologs got confused\n" );
538                         }
539                         else if (pModule->flags & NE_FFLAGS_SINGLEDATA)
540                         {
541                             *fixup_ptr = 0xb8;  /* MOV AX, */
542                             *(WORD *)(fixup_ptr+1) = dgroup;
543                         }
544                     }
545                     else
546                     {
547                         if (pModule->flags & NE_FFLAGS_MULTIPLEDATA) {
548                             fixup_ptr[0] = 0x90; /* non-library: NOPs */
549                             fixup_ptr[1] = 0x90;
550                             fixup_ptr[2] = 0x90;
551                         }
552                     }
553                 } else {
554                     dprintf_fixup( stddeb, "Unknown signature\n" );
555                 }
556             }
557             else
558               dprintf_module( stddeb,"\n");
559             p += (sel == 0xff) ? 6 : 3;  
560         }
561     }
562 }
563
564
565 /***********************************************************************
566  *           NE_InitDLL
567  *
568  * Call the DLL initialization code
569  */
570 static BOOL32 NE_InitDLL( TDB* pTask, HMODULE16 hModule )
571 {
572     NE_MODULE *pModule;
573     SEGTABLEENTRY *pSegTable;
574     CONTEXT context;
575
576     /* Registers at initialization must be:
577      * cx     heap size
578      * di     library instance
579      * ds     data segment if any
580      * es:si  command line (always 0)
581      */
582
583     if (!(pModule = MODULE_GetPtr( hModule ))) return FALSE;
584     pSegTable = NE_SEG_TABLE( pModule );
585
586     if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
587         (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
588
589     /* Call USER signal handler. This is necessary to install a
590      * proper loader for HICON and HCURSOR resources that this DLL 
591      * may contain. InitApp() does this for task modules. */
592
593     if (pTask && pTask->userhandler)
594     {
595         pTask->userhandler( hModule, USIG_DLL_LOAD, 0, pTask->hInstance,
596                             pTask->hQueue );
597     }
598
599     if (!pModule->cs) return TRUE;  /* no initialization code */
600
601     memset( &context, 0, sizeof(context) );
602
603     if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
604     {
605         if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
606         {
607             /* Not SINGLEDATA */
608             fprintf(stderr, "Library is not marked SINGLEDATA\n");
609             exit(1);
610         }
611         else  /* DATA NONE DLL */
612         {
613             DS_reg(&context)  = 0;
614             ECX_reg(&context) = 0;
615         }
616     }
617     else  /* DATA SINGLE DLL */
618     {
619         DS_reg(&context)  = pSegTable[pModule->dgroup-1].selector;
620         ECX_reg(&context) = pModule->heap_size;
621     }
622
623     CS_reg(&context)  = pSegTable[pModule->cs-1].selector;
624     EIP_reg(&context) = pModule->ip;
625     EBP_reg(&context) = OFFSETOF(IF1632_Saved16_ss_sp)
626                           + (WORD)&((STACK16FRAME*)0)->bp;
627     EDI_reg(&context) = DS_reg(&context) ? DS_reg(&context) : hModule;
628
629
630     pModule->cs = 0;  /* Don't initialize it twice */
631     dprintf_dll( stddeb, "Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n", 
632                  CS_reg(&context), IP_reg(&context), DS_reg(&context),
633                  DI_reg(&context), CX_reg(&context) );
634     Callbacks->CallRegisterShortProc( &context, 0 );
635     return TRUE;
636 }
637
638
639 /***********************************************************************
640  *           NE_InitializeDLLs
641  *
642  * Recursively initialize all DLLs (according to the order in which 
643  * they where loaded).
644  */
645 void NE_InitializeDLLs( HMODULE16 hModule )
646 {
647     TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
648     NE_MODULE *pModule;
649     HMODULE16 *pDLL;
650
651     if (!(pModule = MODULE_GetPtr( hModule ))) return;
652     if (pModule->flags & NE_FFLAGS_WIN32) return;
653
654     if (pModule->dlls_to_init)
655     {
656         HGLOBAL16 to_init = pModule->dlls_to_init;
657         pModule->dlls_to_init = 0;
658         for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
659         {
660             NE_InitializeDLLs( *pDLL );
661         }
662         GlobalFree16( to_init );
663     }
664     NE_InitDLL( pTask, hModule );
665 }
666
667
668 /***********************************************************************
669  *           PatchCodeHandle
670  *
671  * Needed for self-loading modules.
672  */
673
674 /* It does nothing */
675 void WINAPI PatchCodeHandle(HANDLE16 hSel)
676 {
677         fprintf(stderr,"PatchCodeHandle(%04x),stub!\n",hSel);
678 }