~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/kernel32/ne_segment.c

Version: ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * NE segment loading
  3  *
  4  * Copyright 1993 Robert J. Amstadt
  5  * Copyright 1995 Alexandre Julliard
  6  *
  7  * This library is free software; you can redistribute it and/or
  8  * modify it under the terms of the GNU Lesser General Public
  9  * License as published by the Free Software Foundation; either
 10  * version 2.1 of the License, or (at your option) any later version.
 11  *
 12  * This library is distributed in the hope that it will be useful,
 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 15  * Lesser General Public License for more details.
 16  *
 17  * You should have received a copy of the GNU Lesser General Public
 18  * License along with this library; if not, write to the Free Software
 19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 20  */
 21 
 22 #include "config.h"
 23 #include "wine/port.h"
 24 
 25 #include <assert.h>
 26 #include <stdio.h>
 27 #include <stdlib.h>
 28 #include <sys/types.h>
 29 #include <fcntl.h>
 30 #ifdef HAVE_UNISTD_H
 31 # include <unistd.h>
 32 #endif
 33 #include <ctype.h>
 34 #include <string.h>
 35 
 36 #include "wine/winbase16.h"
 37 #include "wownt32.h"
 38 #include "winternl.h"
 39 #include "wine/library.h"
 40 #include "kernel_private.h"
 41 #include "kernel16_private.h"
 42 #include "toolhelp.h"
 43 #include "wine/debug.h"
 44 
 45 WINE_DEFAULT_DEBUG_CHANNEL(fixup);
 46 WINE_DECLARE_DEBUG_CHANNEL(dll);
 47 WINE_DECLARE_DEBUG_CHANNEL(module);
 48 
 49 /*
 50  * Relocation table entry
 51  */
 52 struct relocation_entry_s
 53 {
 54     BYTE address_type;    /* Relocation address type */
 55     BYTE relocation_type; /* Relocation type */
 56     WORD offset;          /* Offset in segment to fixup */
 57     WORD target1;         /* Target specification */
 58     WORD target2;         /* Target specification */
 59 };
 60 
 61 /*
 62  * Relocation address types
 63  */
 64 #define NE_RADDR_LOWBYTE      0
 65 #define NE_RADDR_SELECTOR     2
 66 #define NE_RADDR_POINTER32    3
 67 #define NE_RADDR_OFFSET16     5
 68 #define NE_RADDR_POINTER48    11
 69 #define NE_RADDR_OFFSET32     13
 70 
 71 /*
 72  * Relocation types
 73  */
 74 #define NE_RELTYPE_INTERNAL  0
 75 #define NE_RELTYPE_ORDINAL   1
 76 #define NE_RELTYPE_NAME      2
 77 #define NE_RELTYPE_OSFIXUP   3
 78 #define NE_RELFLAG_ADDITIVE  4
 79 
 80 /* Self-loading modules contain this structure in their first segment */
 81 typedef struct
 82 {
 83     WORD      version;       /* Must be "A0" (0x3041) */
 84     WORD      reserved;
 85     FARPROC16 BootApp;       /* startup procedure */
 86     FARPROC16 LoadAppSeg;    /* procedure to load a segment */
 87     FARPROC16 reserved2;
 88     FARPROC16 MyAlloc;       /* memory allocation procedure,
 89                               * wine must write this field */
 90     FARPROC16 EntryAddrProc;
 91     FARPROC16 ExitProc;      /* exit procedure */
 92     WORD      reserved3[4];
 93     FARPROC16 SetOwner;      /* Set Owner procedure, exported by wine */
 94 } SELFLOADHEADER;
 95 
 96 #define SEL(x) ((x)|1)
 97 
 98 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);
 99 
100 
101 /***********************************************************************
102  *           NE_GetRelocAddrName
103  */
104 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
105 {
106     switch(addr_type & 0x7f)
107     {
108     case NE_RADDR_LOWBYTE:   return additive ? "BYTE add" : "BYTE";
109     case NE_RADDR_OFFSET16:  return additive ? "OFFSET16 add" : "OFFSET16";
110     case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
111     case NE_RADDR_SELECTOR:  return additive ? "SELECTOR add" : "SELECTOR";
112     case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
113     case NE_RADDR_OFFSET32:  return additive ? "OFFSET32 add" : "OFFSET32";
114     }
115     return "???";
116 }
117 
118 
119 /***********************************************************************
120  *           NE_OpenFile
121  */
122 static HFILE16 NE_OpenFile( NE_MODULE *pModule )
123 {
124     char *name = NE_MODULE_NAME( pModule );
125     HANDLE handle = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
126                                  NULL, OPEN_EXISTING, 0, 0 );
127 
128     if (handle == INVALID_HANDLE_VALUE)
129     {
130         ERR( "Can't open file '%s' for module %04x\n", name, pModule->self );
131         return HFILE_ERROR;
132     }
133     return Win32HandleToDosFileHandle( handle );
134 }
135 
136 
137 /***********************************************************************
138  *           apply_relocations
139  *
140  * Apply relocations to a segment. Helper for NE_LoadSegment.
141  */
142 static inline BOOL apply_relocations( NE_MODULE *pModule, const struct relocation_entry_s *rep,
143                                       int count, int segnum )
144 {
145     BYTE *func_name;
146     char buffer[256];
147     int i, ordinal;
148     WORD offset, *sp;
149     HMODULE16 module;
150     FARPROC16 address = 0;
151     HMODULE16 *pModuleTable = (HMODULE16 *)((char *)pModule + pModule->ne_modtab);
152     SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
153     SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;
154 
155     /*
156      * Go through the relocation table one entry at a time.
157      */
158     for (i = 0; i < count; i++, rep++)
159     {
160         /*
161          * Get the target address corresponding to this entry.
162          */
163 
164         /* If additive, there is no target chain list. Instead, add source
165            and target */
166         int additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
167         switch (rep->relocation_type & 3)
168         {
169         case NE_RELTYPE_ORDINAL:
170             module = pModuleTable[rep->target1-1];
171             ordinal = rep->target2;
172             address = NE_GetEntryPoint( module, ordinal );
173             if (!address)
174             {
175                 NE_MODULE *pTarget = NE_GetPtr( module );
176                 if (!pTarget)
177                     WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
178                              module, rep->target1,
179                              *((BYTE *)pModule + pModule->ne_restab),
180                              *((BYTE *)pModule + pModule->ne_restab),
181                              (char *)pModule + pModule->ne_restab + 1 );
182                 else
183                 {
184                     ERR("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
185                             *((BYTE *)pTarget + pTarget->ne_restab),
186                             (char *)pTarget + pTarget->ne_restab + 1,
187                             ordinal );
188                     address = (FARPROC16)0xdeadbeef;
189                 }
190             }
191             if (TRACE_ON(fixup))
192             {
193                 NE_MODULE *pTarget = NE_GetPtr( module );
194                 TRACE("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
195                        *((BYTE *)pTarget + pTarget->ne_restab),
196                        (char *)pTarget + pTarget->ne_restab + 1,
197                        ordinal, HIWORD(address), LOWORD(address),
198                        NE_GetRelocAddrName( rep->address_type, additive ) );
199             }
200             break;
201 
202         case NE_RELTYPE_NAME:
203             module = pModuleTable[rep->target1-1];
204             func_name = (BYTE *)pModule + pModule->ne_imptab + rep->target2;
205             memcpy( buffer, func_name+1, *func_name );
206             buffer[*func_name] = '\0';
207             ordinal = NE_GetOrdinal( module, buffer );
208             address = NE_GetEntryPoint( module, ordinal );
209 
210             if (ERR_ON(fixup) && !address)
211             {
212                 NE_MODULE *pTarget = NE_GetPtr( module );
213                 ERR("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
214                     *((BYTE *)pTarget + pTarget->ne_restab),
215                     (char *)pTarget + pTarget->ne_restab + 1, buffer );
216             }
217             if (!address) address = (FARPROC16) 0xdeadbeef;
218             if (TRACE_ON(fixup))
219             {
220                 NE_MODULE *pTarget = NE_GetPtr( module );
221                 TRACE("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
222                        *((BYTE *)pTarget + pTarget->ne_restab),
223                        (char *)pTarget + pTarget->ne_restab + 1,
224                        buffer, HIWORD(address), LOWORD(address),
225                        NE_GetRelocAddrName( rep->address_type, additive ) );
226             }
227             break;
228 
229         case NE_RELTYPE_INTERNAL:
230             if ((rep->target1 & 0xff) == 0xff)
231             {
232                 address  = NE_GetEntryPoint( pModule->self, rep->target2 );
233             }
234             else
235             {
236                 address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
237             }
238 
239             TRACE("%d: %04x:%04x %s\n",
240                   i + 1, HIWORD(address), LOWORD(address),
241                   NE_GetRelocAddrName( rep->address_type, additive ) );
242             break;
243 
244         case NE_RELTYPE_OSFIXUP:
245             /* Relocation type 7:
246              *
247              *    These appear to be used as fixups for the Windows
248              * floating point emulator.  Let's just ignore them and
249              * try to use the hardware floating point.  Linux should
250              * successfully emulate the coprocessor if it doesn't
251              * exist.
252              */
253             TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
254                   i + 1, rep->relocation_type, rep->offset,
255                   rep->target1, rep->target2,
256                   NE_GetRelocAddrName( rep->address_type, additive ) );
257             continue;
258         }
259 
260         offset  = rep->offset;
261 
262         /* Apparently, high bit of address_type is sometimes set; */
263         /* we ignore it for now */
264         if (rep->address_type > NE_RADDR_OFFSET32)
265         {
266             char module[10];
267             GetModuleName16( pModule->self, module, sizeof(module) );
268             ERR("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
269                  module, rep->address_type );
270         }
271 
272         if (additive)
273         {
274             sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
275             TRACE("    %04x:%04x\n", offset, *sp );
276             switch (rep->address_type & 0x7f)
277             {
278             case NE_RADDR_LOWBYTE:
279                 *(BYTE *)sp += LOBYTE((int)address);
280                 break;
281             case NE_RADDR_OFFSET16:
282                 *sp += LOWORD(address);
283                 break;
284             case NE_RADDR_POINTER32:
285                 *sp += LOWORD(address);
286                 *(sp+1) = HIWORD(address);
287                 break;
288             case NE_RADDR_SELECTOR:
289                 /* Borland creates additive records with offset zero. Strange, but OK */
290                 if (*sp)
291                     ERR("Additive selector to %04x.Please report\n",*sp);
292                 else
293                     *sp = HIWORD(address);
294                 break;
295             default:
296                 goto unknown;
297             }
298         }
299         else  /* non-additive fixup */
300         {
301             do
302             {
303                 WORD next_offset;
304 
305                 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
306                 next_offset = *sp;
307                 TRACE("    %04x:%04x\n", offset, *sp );
308                 switch (rep->address_type & 0x7f)
309                 {
310                 case NE_RADDR_LOWBYTE:
311                     *(BYTE *)sp = LOBYTE((int)address);
312                     break;
313                 case NE_RADDR_OFFSET16:
314                     *sp = LOWORD(address);
315                     break;
316                 case NE_RADDR_POINTER32:
317                     *(FARPROC16 *)sp = address;
318                     break;
319                 case NE_RADDR_SELECTOR:
320                     *sp = SELECTOROF(address);
321                     break;
322                 default:
323                     goto unknown;
324                 }
325                 if (next_offset == offset) break;  /* avoid infinite loop */
326                 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
327                 offset = next_offset;
328             } while (offset != 0xffff);
329         }
330     }
331     return TRUE;
332 
333 unknown:
334     WARN("WARNING: %d: unknown ADDR TYPE %d,  "
335          "TYPE %d,  OFFSET %04x,  TARGET %04x %04x\n",
336          i + 1, rep->address_type, rep->relocation_type,
337          rep->offset, rep->target1, rep->target2);
338     return FALSE;
339 }
340 
341 
342 /***********************************************************************
343  *           NE_LoadSegment
344  */
345 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
346 {
347     WORD count;
348     DWORD pos;
349     const struct relocation_entry_s *rep;
350     int size;
351     SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
352     SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;
353 
354     if (pSeg->flags & NE_SEGFLAGS_LOADED)
355     {
356         /* self-loader ? -> already loaded it */
357         if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
358             return TRUE;
359 
360         /* leave, except for DGROUP, as this may be the second instance */
361         if (segnum != pModule->ne_autodata)
362             return TRUE;
363     }
364 
365     if (!pSeg->filepos) return TRUE;  /* No file image, just return */
366 
367     TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
368                     segnum, pSeg->hSeg, pSeg->flags );
369     pos = pSeg->filepos << pModule->ne_align;
370     if (pSeg->size) size = pSeg->size;
371     else size = pSeg->minsize ? pSeg->minsize : 0x10000;
372 
373     if (pModule->ne_flags & NE_FFLAGS_SELFLOAD && segnum > 1)
374     {
375         /* Implement self-loading segments */
376         SELFLOADHEADER *selfloadheader;
377         void *oldstack;
378         HFILE16 hFile16;
379         WORD args[3];
380         DWORD ret;
381 
382         selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
383         oldstack = NtCurrentTeb()->WOW32Reserved;
384         NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
385                                                            0xff00 - sizeof(STACK16FRAME));
386 
387         hFile16 = NE_OpenFile( pModule );
388         TRACE_(dll)("Call LoadAppSegProc(hmodule=0x%04x,hf=%x,segnum=%d)\n",
389                     pModule->self,hFile16,segnum );
390         args[2] = pModule->self;
391         args[1] = hFile16;
392         args[0] = segnum;
393         WOWCallback16Ex( (DWORD)selfloadheader->LoadAppSeg, WCB16_PASCAL, sizeof(args), args, &ret );
394         pSeg->hSeg = LOWORD(ret);
395         TRACE_(dll)("Ret LoadAppSegProc: hSeg=0x%04x\n", pSeg->hSeg);
396         _lclose16( hFile16 );
397         NtCurrentTeb()->WOW32Reserved = oldstack;
398 
399         pSeg->flags |= NE_SEGFLAGS_LOADED;
400         return TRUE;
401     }
402     else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
403     {
404         void *mem = GlobalLock16(pSeg->hSeg);
405         if (!NE_READ_DATA( pModule, mem, pos, size ))
406             return FALSE;
407         pos += size;
408     }
409     else
410     {
411         /*
412           The following bit of code for "iterated segments" was written without
413           any documentation on the format of these segments. It seems to work,
414           but may be missing something.
415         */
416         const char *buff = NE_GET_DATA( pModule, pos, size );
417         const char* curr = buff;
418         char *mem = GlobalLock16(pSeg->hSeg);
419 
420         pos += size;
421         if (buff == NULL) return FALSE;
422 
423         while(curr < buff + size) {
424             unsigned int rept = ((const short *)curr)[0];
425             unsigned int len =  ((const short *)curr)[1];
426 
427             curr += 2*sizeof(short);
428             while (rept--)
429             {
430                 memcpy( mem, curr, len );
431                 mem += len;
432             }
433             curr += len;
434         }
435     }
436 
437     pSeg->flags |= NE_SEGFLAGS_LOADED;
438 
439     /* Perform exported function prolog fixups */
440     NE_FixupSegmentPrologs( pModule, segnum );
441 
442     if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
443         return TRUE;  /* No relocation data, we are done */
444 
445     if (!NE_READ_DATA( pModule, &count, pos, sizeof(count) ) || !count) return TRUE;
446     pos += sizeof(count);
447 
448     TRACE("Fixups for %.*s, segment %d, hSeg %04x\n",
449           *((BYTE *)pModule + pModule->ne_restab),
450           (char *)pModule + pModule->ne_restab + 1,
451           segnum, pSeg->hSeg );
452 
453     if (!(rep = NE_GET_DATA( pModule, pos, count * sizeof(struct relocation_entry_s) )))
454         return FALSE;
455 
456     return apply_relocations( pModule, rep, count, segnum );
457 }
458 
459 
460 /***********************************************************************
461  *           NE_LoadAllSegments
462  */
463 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
464 {
465     int i;
466     SEGTABLEENTRY * pSegTable = NE_SEG_TABLE(pModule);
467 
468     if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
469     {
470         HFILE16 hFile16;
471         HGLOBAL16 sel;
472         /* Handle self-loading modules */
473         SELFLOADHEADER *selfloadheader;
474         HMODULE16 mod = GetModuleHandle16("KERNEL");
475         void *oldstack;
476         WORD args[2];
477 
478         TRACE_(module)("%.*s is a self-loading module!\n",
479                        *((BYTE*)pModule + pModule->ne_restab),
480                        (char *)pModule + pModule->ne_restab + 1);
481         if (!NE_LoadSegment( pModule, 1 )) return FALSE;
482         selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) );
483         selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc");
484         selfloadheader->MyAlloc       = GetProcAddress16(mod,"MyAlloc");
485         selfloadheader->SetOwner      = GetProcAddress16(mod,"FarSetOwner");
486         sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 );
487         pModule->self_loading_sel = SEL(sel);
488         FarSetOwner16( sel, pModule->self );
489         oldstack = NtCurrentTeb()->WOW32Reserved;
490         NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
491                                                            0xff00 - sizeof(STACK16FRAME) );
492 
493         hFile16 = NE_OpenFile(pModule);
494         TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
495               pModule->self,hFile16);
496         args[1] = pModule->self;
497         args[0] = hFile16;
498         WOWCallback16Ex( (DWORD)selfloadheader->BootApp, WCB16_PASCAL, sizeof(args), args, NULL );
499         TRACE_(dll)("Return from CallBootAppProc\n");
500         _lclose16(hFile16);
501         NtCurrentTeb()->WOW32Reserved = oldstack;
502 
503         for (i = 2; i <= pModule->ne_cseg; i++)
504             if (!NE_LoadSegment( pModule, i )) return FALSE;
505     }
506     else
507     {
508         for (i = 1; i <= pModule->ne_cseg; i++)
509             if (!NE_LoadSegment( pModule, i )) return FALSE;
510     }
511     return TRUE;
512 }
513 
514 
515 /***********************************************************************
516  *           NE_FixupSegmentPrologs
517  *
518  * Fixup exported functions prologs of one segment
519  */
520 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
521 {
522     SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
523     ET_BUNDLE *bundle;
524     ET_ENTRY *entry;
525     WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
526     BYTE *pSeg, *pFunc;
527 
528     TRACE("(%d);\n", segnum);
529 
530     if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
531     {
532         pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
533         return;
534     }
535 
536     if (!pModule->ne_autodata) return;
537 
538     if (!(dgroup = SEL(pSegTable[pModule->ne_autodata-1].hSeg))) return;
539 
540     pSeg = MapSL( MAKESEGPTR(sel, 0) );
541 
542     bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->ne_enttab);
543 
544     do {
545         TRACE("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
546         if (!(num_entries = bundle->last - bundle->first))
547             return;
548         entry = (ET_ENTRY *)((BYTE *)bundle+6);
549         while (num_entries--)
550         {
551             /*TRACE("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
552             if (entry->segnum == segnum)
553             {
554                 pFunc = pSeg+entry->offs;
555                 TRACE("pFunc: %p, *(DWORD *)pFunc: %08x, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
556                 if (*(pFunc+2) == 0x90)
557                 {
558                     if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
559                     {
560                         TRACE("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
561                         *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
562                     }
563 
564                     if (*(WORD *)pFunc == 0xd88c)
565                     {
566                         if ((entry->flags & 2)) /* public data ? */
567                         {
568                             TRACE("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
569                             *pFunc = 0xb8; /* mov ax, */
570                             *(WORD *)(pFunc+1) = dgroup;
571                         }
572                         else if ((pModule->ne_flags & NE_FFLAGS_MULTIPLEDATA)
573                                  && (entry->flags & 1)) /* exported ? */
574                         {
575                             TRACE("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
576                             *(WORD *)pFunc = 0x9090; /* nop, nop */
577                         }
578                     }
579                 }
580             }
581             entry++;
582         }
583     } while ( (bundle->next) && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
584 }
585 
586 
587 /***********************************************************************
588  *           PatchCodeHandle (KERNEL.110)
589  *
590  * Needed for self-loading modules.
591  */
592 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
593 {
594     WORD segnum;
595     WORD sel = SEL(hSeg);
596     NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
597     SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
598 
599     TRACE_(module)("(%04x);\n", hSeg);
600 
601     /* find the segment number of the module that belongs to hSeg */
602     for (segnum = 1; segnum <= pModule->ne_cseg; segnum++)
603     {
604         if (SEL(pSegTable[segnum-1].hSeg) == sel)
605         {
606             NE_FixupSegmentPrologs(pModule, segnum);
607             break;
608         }
609     }
610 
611     return MAKELONG(hSeg, sel);
612 }
613 
614 
615 /***********************************************************************
616  *           NE_GetDLLInitParams
617  */
618 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
619                                  WORD *hInst, WORD *ds, WORD *heap )
620 {
621     SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
622 
623     if (!(pModule->ne_flags & NE_FFLAGS_SINGLEDATA))
624     {
625         if (pModule->ne_flags & NE_FFLAGS_MULTIPLEDATA || pModule->ne_autodata)
626         {
627             /* Not SINGLEDATA */
628             ERR_(dll)("Library is not marked SINGLEDATA\n");
629             exit(1);
630         }
631         else  /* DATA NONE DLL */
632         {
633             *ds = 0;
634             *heap = 0;
635         }
636     }
637     else  /* DATA SINGLE DLL */
638     {
639         if (pModule->ne_autodata) {
640             *ds   = SEL(pSegTable[pModule->ne_autodata-1].hSeg);
641             *heap = pModule->ne_heap;
642         }
643         else /* hmm, DLL has no dgroup,
644                 but why has it NE_FFLAGS_SINGLEDATA set ?
645                 Buggy DLL compiler ? */
646         {
647             *ds   = 0;
648             *heap = 0;
649         }
650     }
651 
652     *hInst = *ds ? GlobalHandle16(*ds) : pModule->self;
653 }
654 
655 
656 /***********************************************************************
657  *           NE_InitDLL
658  *
659  * Call the DLL initialization code
660  */
661 static BOOL NE_InitDLL( NE_MODULE *pModule )
662 {
663     SEGTABLEENTRY *pSegTable;
664     WORD hInst, ds, heap;
665     CONTEXT86 context;
666 
667     pSegTable = NE_SEG_TABLE( pModule );
668 
669     if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE) ||
670         (pModule->ne_flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
671 
672     /* Call USER signal handler for Win3.1 compatibility. */
673     NE_CallUserSignalProc( pModule->self, USIG16_DLL_LOAD );
674 
675     if (!SELECTOROF(pModule->ne_csip)) return TRUE;  /* no initialization code */
676 
677 
678     /* Registers at initialization must be:
679      * cx     heap size
680      * di     library instance
681      * ds     data segment if any
682      * es:si  command line (always 0)
683      */
684 
685     memset( &context, 0, sizeof(context) );
686 
687     NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
688 
689     context.Ecx = heap;
690     context.Edi = hInst;
691     context.SegDs = ds;
692     context.SegEs = ds;   /* who knows ... */
693     context.SegFs = wine_get_fs();
694     context.SegGs = wine_get_gs();
695     context.SegCs = SEL(pSegTable[SELECTOROF(pModule->ne_csip)-1].hSeg);
696     context.Eip   = OFFSETOF(pModule->ne_csip);
697     context.Ebp   = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + FIELD_OFFSET(STACK16FRAME,bp);
698 
699     pModule->ne_csip = 0;  /* Don't initialize it twice */
700     TRACE_(dll)("Calling LibMain for %.*s, cs:ip=%04x:%04x ds=%04x di=%04x cx=%04x\n",
701                 *((BYTE*)pModule + pModule->ne_restab),
702                 (char *)pModule + pModule->ne_restab + 1,
703                 context.SegCs, context.Eip, context.SegDs,
704                 LOWORD(context.Edi), LOWORD(context.Ecx) );
705     WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)&context );
706     return TRUE;
707 }
708 
709 /***********************************************************************
710  *           NE_InitializeDLLs
711  *
712  * Recursively initialize all DLLs (according to the order in which
713  * they where loaded).
714  */
715 void NE_InitializeDLLs( HMODULE16 hModule )
716 {
717     NE_MODULE *pModule;
718     HMODULE16 *pDLL;
719 
720     if (!(pModule = NE_GetPtr( hModule ))) return;
721     assert( !(pModule->ne_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( pModule );
734 }
735 
736 
737 /**********************************************************************
738  *          NE_CallUserSignalProc
739  *
740  * According to "Undocumented Windows", the task signal proc is
741  * bypassed for module load/unload notifications, and the USER signal
742  * proc is called directly instead. This is what this function does.
743  */
744 typedef DWORD (WINAPI *pSignalProc)( HANDLE16 module, UINT16 code, UINT16 exit,
745                                      HINSTANCE16 inst, HQUEUE16 queue );
746 
747 void NE_CallUserSignalProc( HMODULE16 hModule, UINT16 code )
748 {
749     FARPROC16 proc;
750     HMODULE16 user = GetModuleHandle16("user.exe");
751 
752     if (!user) return;
753     if ((proc = GetProcAddress16( user, "SignalProc" )))
754     {
755         /* USER is always a builtin dll */
756         pSignalProc sigproc = (pSignalProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)proc ))->target;
757         sigproc( hModule, code, 0, 0, 0 );
758     }
759 }
760 
761 
762 /***********************************************************************
763  *           NE_CallDllEntryPoint
764  *
765  * Call the DllEntryPoint of DLLs with subsystem >= 4.0
766  */
767 typedef DWORD (WINAPI *WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
768 
769 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
770 {
771     WORD hInst, ds, heap;
772     FARPROC16 entryPoint;
773 
774     if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE)) return;
775     if (!(pModule->ne_flags & NE_FFLAGS_BUILTIN) && pModule->ne_expver < 0x0400) return;
776     if (!(entryPoint = GetProcAddress16( pModule->self, "DllEntryPoint" ))) return;
777 
778     NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
779 
780     TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
781                  NE_MODULE_NAME( pModule ),
782                  SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
783 
784     if ( pModule->ne_flags & NE_FFLAGS_BUILTIN )
785     {
786         WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target;
787 
788         entryProc( dwReason, hInst, ds, heap, 0, 0 );
789     }
790     else
791     {
792         CONTEXT86 context;
793         WORD args[8];
794 
795         memset( &context, 0, sizeof(context) );
796         context.SegDs = ds;
797         context.SegEs = ds;   /* who knows ... */
798         context.SegFs = wine_get_fs();
799         context.SegGs = wine_get_gs();
800         context.SegCs = HIWORD(entryPoint);
801         context.Eip   = LOWORD(entryPoint);
802         context.Ebp   = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + FIELD_OFFSET(STACK16FRAME,bp);
803 
804         args[7] = HIWORD(dwReason);
805         args[6] = LOWORD(dwReason);
806         args[5] = hInst;
807         args[4] = ds;
808         args[3] = heap;
809         args[2] = 0;     /* HIWORD(dwReserved1) */
810         args[1] = 0;     /* LOWORD(dwReserved1) */
811         args[0] = 0;     /* wReserved2 */
812         WOWCallback16Ex( 0, WCB16_REGS, sizeof(args), args, (DWORD *)&context );
813     }
814 }
815 
816 /***********************************************************************
817  *           NE_DllProcessAttach
818  *
819  * Call the DllEntryPoint of all modules this one (recursively)
820  * depends on, according to the order in which they were loaded.
821  *
822  * Note that --as opposed to the PE module case-- there is no notion
823  * of 'module loaded into a process' for NE modules, and hence we
824  * have no place to store the fact that the DllEntryPoint of a
825  * given module was already called on behalf of this process (e.g.
826  * due to some earlier LoadLibrary16 call).
827  *
828  * Thus, we just call the DllEntryPoint twice in that case.  Win9x
829  * appears to behave this way as well ...
830  *
831  * This routine must only be called with the Win16Lock held.
832  *
833  * FIXME:  We should actually abort loading in case the DllEntryPoint
834  *         returns FALSE ...
835  *
836  */
837 
838 struct ne_init_list
839 {
840     int count;
841     int size;
842     NE_MODULE **module;
843 };
844 
845 static void add_to_init_list( struct ne_init_list *list, NE_MODULE *hModule )
846 {
847     NE_MODULE **newModule = NULL;
848     if ( list->count == list->size )
849     {
850         int newSize = list->size + 128;
851 
852         if (list->module) 
853             newModule = HeapReAlloc( GetProcessHeap(), 0,
854                                              list->module, newSize*sizeof(NE_MODULE *) );
855         else
856             newModule = HeapAlloc( GetProcessHeap(), 0,
857                                              newSize*sizeof(NE_MODULE *) );
858         if ( !newModule )
859         {
860             FIXME_(dll)("Out of memory!\n");
861             return;
862         }
863 
864         list->module = newModule;
865         list->size   = newSize;
866     }
867 
868     list->module[list->count++] = hModule;
869 }
870 
871 static void free_init_list( struct ne_init_list *list )
872 {
873     if ( list->module )
874     {
875         HeapFree( GetProcessHeap(), 0, list->module );
876         memset( list, 0, sizeof(*list) );
877     }
878 }
879 
880 static void fill_init_list( struct ne_init_list *list, HMODULE16 hModule )
881 {
882     NE_MODULE *pModule;
883     HMODULE16 *pModRef;
884     int i;
885 
886     if (!(pModule = NE_GetPtr( hModule ))) return;
887     assert( !(pModule->ne_flags & NE_FFLAGS_WIN32) );
888 
889     /* Never add a module twice */
890     for ( i = 0; i < list->count; i++ )
891         if ( <