Fixed some issues found by winapi_check.
[wine] / loader / ne / segment.c
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "wine/library.h"
38 #include "global.h"
39 #include "task.h"
40 #include "file.h"
41 #include "module.h"
42 #include "stackframe.h"
43 #include "builtin16.h"
44 #include "wine/debug.h"
45
46 WINE_DECLARE_DEBUG_CHANNEL(dll);
47 WINE_DECLARE_DEBUG_CHANNEL(fixup);
48 WINE_DECLARE_DEBUG_CHANNEL(module);
49 WINE_DECLARE_DEBUG_CHANNEL(segment);
50
51 /*
52  * Relocation table entry
53  */
54 struct relocation_entry_s
55 {
56     BYTE address_type;    /* Relocation address type */
57     BYTE relocation_type; /* Relocation type */
58     WORD offset;          /* Offset in segment to fixup */
59     WORD target1;         /* Target specification */
60     WORD target2;         /* Target specification */
61 };
62
63 /*
64  * Relocation address types
65  */
66 #define NE_RADDR_LOWBYTE      0
67 #define NE_RADDR_SELECTOR     2
68 #define NE_RADDR_POINTER32    3
69 #define NE_RADDR_OFFSET16     5
70 #define NE_RADDR_POINTER48    11
71 #define NE_RADDR_OFFSET32     13
72
73 /*
74  * Relocation types
75  */
76 #define NE_RELTYPE_INTERNAL  0
77 #define NE_RELTYPE_ORDINAL   1
78 #define NE_RELTYPE_NAME      2
79 #define NE_RELTYPE_OSFIXUP   3
80 #define NE_RELFLAG_ADDITIVE  4
81
82 #define SEL(x) ((x)|1)
83
84 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);
85
86 /* ### start build ### */
87 extern WORD CALLBACK NE_CallTo16_word_ww(FARPROC16,WORD,WORD);
88 extern WORD CALLBACK NE_CallTo16_word_www(FARPROC16,WORD,WORD,WORD);
89 /* ### stop build ### */
90
91 /***********************************************************************
92  *           NE_GetRelocAddrName
93  */
94 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
95 {
96     switch(addr_type & 0x7f)
97     {
98     case NE_RADDR_LOWBYTE:   return additive ? "BYTE add" : "BYTE";
99     case NE_RADDR_OFFSET16:  return additive ? "OFFSET16 add" : "OFFSET16";
100     case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
101     case NE_RADDR_SELECTOR:  return additive ? "SELECTOR add" : "SELECTOR";
102     case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
103     case NE_RADDR_OFFSET32:  return additive ? "OFFSET32 add" : "OFFSET32";
104     }
105     return "???";
106 }
107
108
109 /***********************************************************************
110  *           NE_LoadSegment
111  */
112 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
113 {
114     SEGTABLEENTRY *pSegTable, *pSeg;
115     WORD *pModuleTable;
116     WORD count, i, offset, next_offset;
117     HMODULE16 module;
118     FARPROC16 address = 0;
119     HANDLE hf;
120     DWORD res;
121     struct relocation_entry_s *rep, *reloc_entries;
122     BYTE *func_name;
123     int size;
124     char* mem;
125
126     char buffer[256];
127     int ordinal, additive;
128     unsigned short *sp;
129
130     pSegTable = NE_SEG_TABLE( pModule );
131     pSeg = pSegTable + segnum - 1;
132
133     if (pSeg->flags & NE_SEGFLAGS_LOADED)
134     {
135         /* self-loader ? -> already loaded it */
136         if (pModule->flags & NE_FFLAGS_SELFLOAD)
137             return TRUE;
138
139         /* leave, except for DGROUP, as this may be the second instance */
140         if (segnum != pModule->dgroup)
141             return TRUE;
142     }
143
144     if (!pSeg->filepos) return TRUE;  /* No file image, just return */
145
146     pModuleTable = NE_MODULE_TABLE( pModule );
147
148     hf = NE_OpenFile( pModule );
149     TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
150                     segnum, pSeg->hSeg, pSeg->flags );
151     SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
152     if (pSeg->size) size = pSeg->size;
153     else size = pSeg->minsize ? pSeg->minsize : 0x10000;
154     mem = GlobalLock16(pSeg->hSeg);
155     if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
156     {
157         /* Implement self-loading segments */
158         SELFLOADHEADER *selfloadheader;
159         DWORD oldstack;
160         HANDLE hFile32;
161         HFILE16 hFile16;
162
163         selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
164         oldstack = NtCurrentTeb()->cur_stack;
165         NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
166                                                0xff00 - sizeof(STACK16FRAME));
167
168         TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
169                 pModule->self,hf,segnum );
170         DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
171                          0, FALSE, DUPLICATE_SAME_ACCESS );
172         hFile16 = Win32HandleToDosFileHandle( hFile32 );
173         pSeg->hSeg = NE_CallTo16_word_www( selfloadheader->LoadAppSeg,
174                                            pModule->self, hFile16, segnum );
175         TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
176         _lclose16( hFile16 );
177         NtCurrentTeb()->cur_stack = oldstack;
178     }
179     else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
180         ReadFile(hf, mem, size, &res, NULL);
181     else {
182       /*
183          The following bit of code for "iterated segments" was written without
184          any documentation on the format of these segments. It seems to work,
185          but may be missing something. If you have any doc please either send
186          it to me or fix the code yourself. gfm@werple.mira.net.au
187       */
188       char* buff = HeapAlloc(GetProcessHeap(), 0, size);
189       char* curr = buff;
190
191       if(buff == NULL) {
192           WARN_(dll)("Memory exausted!");
193           goto fail;
194       }
195
196       ReadFile(hf, buff, size, &res, NULL);
197       while(curr < buff + size) {
198         unsigned int rept = *((short*) curr)++;
199         unsigned int len = *((short*) curr)++;
200         for(; rept > 0; rept--) {
201           char* bytes = curr;
202           unsigned int byte;
203           for(byte = 0; byte < len; byte++)
204             *mem++ = *bytes++;
205         }
206         curr += len;
207       }
208       HeapFree(GetProcessHeap(), 0, buff);
209     }
210
211     pSeg->flags |= NE_SEGFLAGS_LOADED;
212
213     /* Perform exported function prolog fixups */
214     NE_FixupSegmentPrologs( pModule, segnum );
215
216     if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
217         goto succeed;  /* No relocation data, we are done */
218
219     ReadFile(hf, &count, sizeof(count), &res, NULL);
220     if (!count) goto succeed;
221
222     TRACE_(fixup)("Fixups for %.*s, segment %d, hSeg %04x\n",
223                    *((BYTE *)pModule + pModule->name_table),
224                    (char *)pModule + pModule->name_table + 1,
225                    segnum, pSeg->hSeg );
226     TRACE_(segment)("Fixups for %.*s, segment %d, hSeg %04x\n",
227                    *((BYTE *)pModule + pModule->name_table),
228                    (char *)pModule + pModule->name_table + 1,
229                    segnum, pSeg->hSeg );
230
231     reloc_entries = (struct relocation_entry_s *)HeapAlloc(GetProcessHeap(), 0, count * sizeof(struct relocation_entry_s));
232     if(reloc_entries == NULL) {
233         WARN_(fixup)("Not enough memory for relocation entries!");
234         goto fail;
235     }
236     if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
237         (res != count * sizeof(struct relocation_entry_s)))
238     {
239         WARN_(fixup)("Unable to read relocation information\n" );
240         goto fail;
241     }
242
243     /*
244      * Go through the relocation table one entry at a time.
245      */
246     rep = reloc_entries;
247     for (i = 0; i < count; i++, rep++)
248     {
249         /*
250          * Get the target address corresponding to this entry.
251          */
252
253         /* If additive, there is no target chain list. Instead, add source
254            and target */
255         additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
256         rep->relocation_type &= 0x3;
257
258         switch (rep->relocation_type)
259         {
260           case NE_RELTYPE_ORDINAL:
261             module = pModuleTable[rep->target1-1];
262             ordinal = rep->target2;
263             address = NE_GetEntryPoint( module, ordinal );
264             if (!address)
265             {
266                 NE_MODULE *pTarget = NE_GetPtr( module );
267                 if (!pTarget)
268                     WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
269                              module, rep->target1,
270                              *((BYTE *)pModule + pModule->name_table),
271                              *((BYTE *)pModule + pModule->name_table),
272                              (char *)pModule + pModule->name_table + 1 );
273                 else
274                 {
275                     ERR_(fixup)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
276                             *((BYTE *)pTarget + pTarget->name_table),
277                             (char *)pTarget + pTarget->name_table + 1,
278                             ordinal );
279                     address = (FARPROC16)0xdeadbeef;
280                 }
281             }
282             if (TRACE_ON(fixup))
283             {
284                 NE_MODULE *pTarget = NE_GetPtr( module );
285                 TRACE_(fixup)("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
286                        *((BYTE *)pTarget + pTarget->name_table),
287                        (char *)pTarget + pTarget->name_table + 1,
288                        ordinal, HIWORD(address), LOWORD(address),
289                        NE_GetRelocAddrName( rep->address_type, additive ) );
290             }
291             break;
292
293           case NE_RELTYPE_NAME:
294             module = pModuleTable[rep->target1-1];
295             func_name = (char *)pModule + pModule->import_table + rep->target2;
296             memcpy( buffer, func_name+1, *func_name );
297             buffer[*func_name] = '\0';
298             func_name = buffer;
299             ordinal = NE_GetOrdinal( module, func_name );
300             address = NE_GetEntryPoint( module, ordinal );
301
302             if (ERR_ON(fixup) && !address)
303             {
304                 NE_MODULE *pTarget = NE_GetPtr( module );
305                 ERR_(fixup)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
306                     *((BYTE *)pTarget + pTarget->name_table),
307                     (char *)pTarget + pTarget->name_table + 1, func_name );
308             }
309             if (!address) address = (FARPROC16) 0xdeadbeef;
310             if (TRACE_ON(fixup))
311             {
312                 NE_MODULE *pTarget = NE_GetPtr( module );
313                 TRACE_(fixup)("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
314                        *((BYTE *)pTarget + pTarget->name_table),
315                        (char *)pTarget + pTarget->name_table + 1,
316                        func_name, HIWORD(address), LOWORD(address),
317                        NE_GetRelocAddrName( rep->address_type, additive ) );
318             }
319             break;
320
321           case NE_RELTYPE_INTERNAL:
322             if ((rep->target1 & 0xff) == 0xff)
323             {
324                 address  = NE_GetEntryPoint( pModule->self, rep->target2 );
325             }
326             else
327             {
328                 address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
329             }
330
331             TRACE_(fixup)("%d: %04x:%04x %s\n",
332                    i + 1, HIWORD(address), LOWORD(address),
333                    NE_GetRelocAddrName( rep->address_type, additive ) );
334             break;
335
336           case NE_RELTYPE_OSFIXUP:
337             /* Relocation type 7:
338              *
339              *    These appear to be used as fixups for the Windows
340              * floating point emulator.  Let's just ignore them and
341              * try to use the hardware floating point.  Linux should
342              * successfully emulate the coprocessor if it doesn't
343              * exist.
344              */
345             TRACE_(fixup)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
346                    i + 1, rep->relocation_type, rep->offset,
347                    rep->target1, rep->target2,
348                    NE_GetRelocAddrName( rep->address_type, additive ) );
349             continue;
350         }
351
352         offset  = rep->offset;
353
354         /* Apparently, high bit of address_type is sometimes set; */
355         /* we ignore it for now */
356         if (rep->address_type > NE_RADDR_OFFSET32)
357         {
358             char module[10];
359             GetModuleName16( pModule->self, module, sizeof(module) );
360             ERR_(fixup)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
361                  module, rep->address_type );
362         }
363
364         if (additive)
365         {
366             sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
367             TRACE_(fixup)("    %04x:%04x\n", offset, *sp );
368             switch (rep->address_type & 0x7f)
369             {
370             case NE_RADDR_LOWBYTE:
371                 *(BYTE *)sp += LOBYTE((int)address);
372                 break;
373             case NE_RADDR_OFFSET16:
374                 *sp += LOWORD(address);
375                 break;
376             case NE_RADDR_POINTER32:
377                 *sp += LOWORD(address);
378                 *(sp+1) = HIWORD(address);
379                 break;
380             case NE_RADDR_SELECTOR:
381                 /* Borland creates additive records with offset zero. Strange, but OK */
382                 if (*sp)
383                     ERR_(fixup)("Additive selector to %04x.Please report\n",*sp);
384                 else
385                     *sp = HIWORD(address);
386                 break;
387             default:
388                 goto unknown;
389             }
390         }
391         else  /* non-additive fixup */
392         {
393             do
394             {
395                 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
396                 next_offset = *sp;
397                 TRACE_(fixup)("    %04x:%04x\n", offset, *sp );
398                 switch (rep->address_type & 0x7f)
399                 {
400                 case NE_RADDR_LOWBYTE:
401                     *(BYTE *)sp = LOBYTE((int)address);
402                     break;
403                 case NE_RADDR_OFFSET16:
404                     *sp = LOWORD(address);
405                     break;
406                 case NE_RADDR_POINTER32:
407                     *(FARPROC16 *)sp = address;
408                     break;
409                 case NE_RADDR_SELECTOR:
410                     *sp = SELECTOROF(address);
411                     break;
412                 default:
413                     goto unknown;
414                 }
415                 if (next_offset == offset) break;  /* avoid infinite loop */
416                 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
417                 offset = next_offset;
418             } while (offset != 0xffff);
419         }
420     }
421
422     HeapFree(GetProcessHeap(), 0, reloc_entries);
423
424 succeed:
425     CloseHandle(hf);
426     return TRUE;
427
428 unknown:
429     WARN_(fixup)("WARNING: %d: unknown ADDR TYPE %d,  "
430          "TYPE %d,  OFFSET %04x,  TARGET %04x %04x\n",
431          i + 1, rep->address_type, rep->relocation_type,
432          rep->offset, rep->target1, rep->target2);
433     HeapFree(GetProcessHeap(), 0, reloc_entries);
434
435 fail:
436     CloseHandle(hf);
437     return FALSE;
438 }
439
440
441 /***********************************************************************
442  *           NE_LoadAllSegments
443  */
444 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
445 {
446     int i;
447     SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
448
449     if (pModule->flags & NE_FFLAGS_SELFLOAD)
450     {
451         HANDLE hf;
452         HFILE16 hFile16;
453         HGLOBAL16 sel;
454         /* Handle self-loading modules */
455         SELFLOADHEADER *selfloadheader;
456         HMODULE16 mod = GetModuleHandle16("KERNEL");
457         DWORD oldstack;
458
459         TRACE_(module)("%.*s is a self-loading module!\n",
460                      *((BYTE*)pModule + pModule->name_table),
461                      (char *)pModule + pModule->name_table + 1);
462         if (!NE_LoadSegment( pModule, 1 )) return FALSE;
463         selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) );
464         selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc");
465         selfloadheader->MyAlloc       = GetProcAddress16(mod,"MyAlloc");
466         selfloadheader->SetOwner      = GetProcAddress16(mod,"FarSetOwner");
467         sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 );
468         pModule->self_loading_sel = SEL(sel);
469         FarSetOwner16( sel, pModule->self );
470         oldstack = NtCurrentTeb()->cur_stack;
471         NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
472                                                0xff00 - sizeof(STACK16FRAME) );
473
474         hf = NE_OpenFile(pModule);
475         hFile16 = Win32HandleToDosFileHandle( hf );
476         TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
477               pModule->self,hFile16);
478         NE_CallTo16_word_ww(selfloadheader->BootApp, pModule->self,hFile16);
479         TRACE_(dll)("Return from CallBootAppProc\n");
480         _lclose16(hFile16);
481         NtCurrentTeb()->cur_stack = oldstack;
482
483         for (i = 2; i <= pModule->seg_count; i++)
484             if (!NE_LoadSegment( pModule, i )) return FALSE;
485     }
486     else
487     {
488         for (i = 1; i <= pModule->seg_count; i++)
489             if (!NE_LoadSegment( pModule, i )) return FALSE;
490     }
491     return TRUE;
492 }
493
494
495 /***********************************************************************
496  *           NE_FixupSegmentPrologs
497  *
498  * Fixup exported functions prologs of one segment
499  */
500 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
501 {
502     SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
503     ET_BUNDLE *bundle;
504     ET_ENTRY *entry;
505     WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
506     BYTE *pSeg, *pFunc;
507
508     TRACE_(module)("(%d);\n", segnum);
509
510     if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
511     {
512         pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
513         return;
514     }
515
516     if (!pModule->dgroup) return;
517
518     if (!(dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg))) return;
519
520     pSeg = MapSL( MAKESEGPTR(sel, 0) );
521
522     bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);
523
524     do {
525         TRACE_(module)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
526         if (!(num_entries = bundle->last - bundle->first))
527             return;
528         entry = (ET_ENTRY *)((BYTE *)bundle+6);
529         while (num_entries--)
530     {
531             /*TRACE_(module)("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
532             if (entry->segnum == segnum)
533         {
534                 pFunc = ((BYTE *)pSeg+entry->offs);
535                 TRACE_(module)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
536                 if (*(pFunc+2) == 0x90)
537         {
538                     if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
539                     {
540                         TRACE_(module)("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
541                         *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
542         }
543
544                     if (*(WORD *)pFunc == 0xd88c)
545                         {
546                         if ((entry->flags & 2)) /* public data ? */
547                         {
548                             TRACE_(module)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
549                             *pFunc = 0xb8; /* mov ax, */
550                             *(WORD *)(pFunc+1) = dgroup;
551                     }
552                     else
553                         if ((pModule->flags & NE_FFLAGS_MULTIPLEDATA)
554                         && (entry->flags & 1)) /* exported ? */
555                     {
556                             TRACE_(module)("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
557                             *(WORD *)pFunc = 0x9090; /* nop, nop */
558                         }
559                     }
560                 }
561             }
562             entry++;
563         }
564     } while ( (bundle->next)
565          && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
566 }
567
568
569 /***********************************************************************
570  *           PatchCodeHandle (KERNEL.110)
571  *
572  * Needed for self-loading modules.
573  */
574 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
575 {
576     WORD segnum;
577     WORD sel = SEL(hSeg);
578     NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
579     SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
580
581     TRACE_(module)("(%04x);\n", hSeg);
582
583     /* find the segment number of the module that belongs to hSeg */
584     for (segnum = 1; segnum <= pModule->seg_count; segnum++)
585     {
586         if (SEL(pSegTable[segnum-1].hSeg) == sel)
587         {
588             NE_FixupSegmentPrologs(pModule, segnum);
589             break;
590         }
591     }
592
593     return MAKELONG(hSeg, sel);
594 }
595
596
597 /***********************************************************************
598  *           NE_GetDLLInitParams
599  */
600 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
601                                  WORD *hInst, WORD *ds, WORD *heap )
602 {
603     SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
604
605     if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
606     {
607         if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
608         {
609             /* Not SINGLEDATA */
610             ERR_(dll)("Library is not marked SINGLEDATA\n");
611             exit(1);
612         }
613         else  /* DATA NONE DLL */
614         {
615             *ds = 0;
616             *heap = 0;
617         }
618     }
619     else  /* DATA SINGLE DLL */
620     {
621         if (pModule->dgroup) {
622             *ds   = SEL(pSegTable[pModule->dgroup-1].hSeg);
623             *heap = pModule->heap_size;
624         }
625         else /* hmm, DLL has no dgroup,
626                 but why has it NE_FFLAGS_SINGLEDATA set ?
627                 Buggy DLL compiler ? */
628         {
629             *ds   = 0;
630             *heap = 0;
631         }
632     }
633
634     *hInst = *ds ? GlobalHandle16(*ds) : pModule->self;
635 }
636
637
638 /***********************************************************************
639  *           NE_InitDLL
640  *
641  * Call the DLL initialization code
642  */
643 static BOOL NE_InitDLL( NE_MODULE *pModule )
644 {
645     SEGTABLEENTRY *pSegTable;
646     WORD hInst, ds, heap;
647     CONTEXT86 context;
648
649     pSegTable = NE_SEG_TABLE( pModule );
650
651     if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
652         (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
653
654     /* Call USER signal handler for Win3.1 compatibility. */
655     TASK_CallTaskSignalProc( USIG16_DLL_LOAD, pModule->self );
656
657     if (!pModule->cs) return TRUE;  /* no initialization code */
658
659
660     /* Registers at initialization must be:
661      * cx     heap size
662      * di     library instance
663      * ds     data segment if any
664      * es:si  command line (always 0)
665      */
666
667     memset( &context, 0, sizeof(context) );
668
669     NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
670
671     context.Ecx = heap;
672     context.Edi = hInst;
673     context.SegDs  = ds;
674     context.SegEs  = ds;   /* who knows ... */
675
676     context.SegCs  = SEL(pSegTable[pModule->cs-1].hSeg);
677     context.Eip = pModule->ip;
678     context.Ebp = OFFSETOF(NtCurrentTeb()->cur_stack) + (WORD)&((STACK16FRAME*)0)->bp;
679
680
681     pModule->cs = 0;  /* Don't initialize it twice */
682     TRACE_(dll)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
683                  context.SegCs, context.Eip, context.SegDs,
684                  LOWORD(context.Edi), LOWORD(context.Ecx) );
685     wine_call_to_16_regs_short( &context, 0 );
686     return TRUE;
687 }
688
689 /***********************************************************************
690  *           NE_InitializeDLLs
691  *
692  * Recursively initialize all DLLs (according to the order in which
693  * they where loaded).
694  */
695 void NE_InitializeDLLs( HMODULE16 hModule )
696 {
697     NE_MODULE *pModule;
698     HMODULE16 *pDLL;
699
700     if (!(pModule = NE_GetPtr( hModule ))) return;
701     assert( !(pModule->flags & NE_FFLAGS_WIN32) );
702
703     if (pModule->dlls_to_init)
704     {
705         HGLOBAL16 to_init = pModule->dlls_to_init;
706         pModule->dlls_to_init = 0;
707         for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
708         {
709             NE_InitializeDLLs( *pDLL );
710         }
711         GlobalFree16( to_init );
712     }
713     NE_InitDLL( pModule );
714 }
715
716
717 /***********************************************************************
718  *           NE_CallDllEntryPoint
719  *
720  * Call the DllEntryPoint of DLLs with subsystem >= 4.0
721  */
722 typedef DWORD (WINAPI *WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
723
724 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
725 {
726     WORD hInst, ds, heap;
727     FARPROC16 entryPoint;
728
729     if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) return;
730     if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
731     if (!(entryPoint = GetProcAddress16( pModule->self, "DllEntryPoint" ))) return;
732
733     NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
734
735     TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
736                  NE_MODULE_NAME( pModule ),
737                  SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
738
739     if ( pModule->flags & NE_FFLAGS_BUILTIN )
740     {
741         WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target;
742
743         entryProc( dwReason, hInst, ds, heap, 0, 0 );
744     }
745     else
746     {
747         LPBYTE stack = (LPBYTE)CURRENT_STACK16;
748         CONTEXT86 context;
749
750         memset( &context, 0, sizeof(context) );
751         context.SegDs = ds;
752         context.SegEs = ds;   /* who knows ... */
753
754         context.SegCs = HIWORD(entryPoint);
755         context.Eip = LOWORD(entryPoint);
756         context.Ebp =  OFFSETOF( NtCurrentTeb()->cur_stack )
757                              + (WORD)&((STACK16FRAME*)0)->bp;
758
759         *(DWORD *)(stack -  4) = dwReason;      /* dwReason */
760         *(WORD *) (stack -  6) = hInst;         /* hInst */
761         *(WORD *) (stack -  8) = ds;            /* wDS */
762         *(WORD *) (stack - 10) = heap;          /* wHeapSize */
763         *(DWORD *)(stack - 14) = 0;             /* dwReserved1 */
764         *(WORD *) (stack - 16) = 0;             /* wReserved2 */
765
766         wine_call_to_16_regs_short( &context, 16 );
767     }
768 }
769
770 /***********************************************************************
771  *           NE_DllProcessAttach
772  *
773  * Call the DllEntryPoint of all modules this one (recursively)
774  * depends on, according to the order in which they were loaded.
775  *
776  * Note that --as opposed to the PE module case-- there is no notion
777  * of 'module loaded into a process' for NE modules, and hence we
778  * have no place to store the fact that the DllEntryPoint of a
779  * given module was already called on behalf of this process (e.g.
780  * due to some earlier LoadLibrary16 call).
781  *
782  * Thus, we just call the DllEntryPoint twice in that case.  Win9x
783  * appears to behave this way as well ...
784  *
785  * This routine must only be called with the Win16Lock held.
786  *
787  * FIXME:  We should actually abort loading in case the DllEntryPoint
788  *         returns FALSE ...
789  *
790  */
791
792 struct ne_init_list
793 {
794     int count;
795     int size;
796     NE_MODULE **module;
797 };
798
799 static void add_to_init_list( struct ne_init_list *list, NE_MODULE *hModule )
800 {
801     if ( list->count == list->size )
802     {
803         int newSize = list->size + 128;
804         NE_MODULE **newModule = HeapReAlloc( GetProcessHeap(), 0,
805                                              list->module, newSize*sizeof(NE_MODULE *) );
806         if ( !newModule )
807         {
808             FIXME_(dll)("Out of memory!");
809             return;
810         }
811
812         list->module = newModule;
813         list->size   = newSize;
814     }
815
816     list->module[list->count++] = hModule;
817 }
818
819 static void free_init_list( struct ne_init_list *list )
820 {
821     if ( list->module )
822     {
823         HeapFree( GetProcessHeap(), 0, list->module );
824         memset( list, 0, sizeof(*list) );
825     }
826 }
827
828 static void fill_init_list( struct ne_init_list *list, HMODULE16 hModule )
829 {
830     NE_MODULE *pModule;
831     WORD *pModRef;
832     int i;
833
834     if (!(pModule = NE_GetPtr( hModule ))) return;
835     assert( !(pModule->flags & NE_FFLAGS_WIN32) );
836
837     /* Never add a module twice */
838     for ( i = 0; i < list->count; i++ )
839         if ( list->module[i] == pModule )
840             return;
841
842     /* Check for recursive call */
843     if ( pModule->misc_flags & 0x80 ) return;
844
845     TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
846
847     /* Tag current module to prevent recursive loop */
848     pModule->misc_flags |= 0x80;
849
850     /* Recursively attach all DLLs this one depends on */
851     pModRef = NE_MODULE_TABLE( pModule );
852     for ( i = 0; i < pModule->modref_count; i++ )
853         if ( pModRef[i] )
854             fill_init_list( list, (HMODULE16)pModRef[i] );
855
856     /* Add current module */
857     add_to_init_list( list, pModule );
858
859     /* Remove recursion flag */
860     pModule->misc_flags &= ~0x80;
861
862     TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
863 }
864
865 static void call_init_list( struct ne_init_list *list )
866 {
867     int i;
868     for ( i = 0; i < list->count; i++ )
869         NE_CallDllEntryPoint( list->module[i], DLL_PROCESS_ATTACH );
870 }
871
872 void NE_DllProcessAttach( HMODULE16 hModule )
873 {
874     struct ne_init_list list;
875     memset( &list, 0, sizeof(list) );
876
877     fill_init_list( &list, hModule );
878     call_init_list( &list );
879     free_init_list( &list );
880 }
881
882
883 /***********************************************************************
884  *           NE_Ne2MemFlags
885  *
886  * This function translates NE segment flags to GlobalAlloc flags
887  */
888 static WORD NE_Ne2MemFlags(WORD flags)
889 {
890     WORD memflags = 0;
891 #if 1
892     if (flags & NE_SEGFLAGS_DISCARDABLE)
893       memflags |= GMEM_DISCARDABLE;
894     if (flags & NE_SEGFLAGS_MOVEABLE ||
895         ( ! (flags & NE_SEGFLAGS_DATA) &&
896           ! (flags & NE_SEGFLAGS_LOADED) &&
897           ! (flags & NE_SEGFLAGS_ALLOCATED)
898          )
899         )
900       memflags |= GMEM_MOVEABLE;
901     memflags |= GMEM_ZEROINIT;
902 #else
903     memflags = GMEM_ZEROINIT | GMEM_FIXED;
904 #endif
905     return memflags;
906 }
907
908 /***********************************************************************
909  *           MyAlloc   (KERNEL.668) Wine-specific export
910  *
911  * MyAlloc() function for self-loading apps.
912  */
913 DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
914 {
915     WORD size = wSize << wElem;
916     HANDLE16 hMem = 0;
917
918     if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
919         hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
920
921     if ( ((wFlags & 0x7) != 0x1) && /* DATA */
922          ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
923     {
924         WORD hSel = SEL(hMem);
925         WORD access = SelectorAccessRights16(hSel,0,0);
926
927         access |= 2<<2; /* SEGMENT_CODE */
928         SelectorAccessRights16(hSel,1,access);
929     }
930     if (size)
931         return MAKELONG( hMem, SEL(hMem) );
932     else
933         return MAKELONG( 0, hMem );
934 }
935
936 /***********************************************************************
937  *           NE_GetInstance
938  */
939 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
940 {
941     if ( !pModule->dgroup )
942         return pModule->self;
943     else
944     {
945         SEGTABLEENTRY *pSeg;
946         pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
947         return pSeg->hSeg;
948     }
949 }
950
951 /***********************************************************************
952  *           NE_CreateSegment
953  */
954 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
955 {
956     SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
957     int minsize;
958     unsigned char selflags;
959
960     assert( !(pModule->flags & NE_FFLAGS_WIN32) );
961
962     if ( segnum < 1 || segnum > pModule->seg_count )
963         return FALSE;
964
965     if ( (pModule->flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
966         return TRUE;    /* selfloader allocates segment itself */
967
968     if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->dgroup )
969         return TRUE;    /* all but DGROUP only allocated once */
970
971     minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
972     if ( segnum == pModule->ss )     minsize += pModule->stack_size;
973     if ( segnum == pModule->dgroup ) minsize += pModule->heap_size;
974
975     selflags = (pSeg->flags & NE_SEGFLAGS_DATA) ? WINE_LDT_FLAGS_DATA : WINE_LDT_FLAGS_CODE;
976     if (pSeg->flags & NE_SEGFLAGS_32BIT) selflags |= WINE_LDT_FLAGS_32BIT;
977     pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags), minsize, pModule->self, selflags );
978     if (!pSeg->hSeg) return FALSE;
979
980     pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
981     return TRUE;
982 }
983
984 /***********************************************************************
985  *           NE_CreateAllSegments
986  */
987 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
988 {
989     int i;
990     for ( i = 1; i <= pModule->seg_count; i++ )
991         if ( !NE_CreateSegment( pModule, i ) )
992             return FALSE;
993
994     pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
995                             (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
996     return TRUE;
997 }
998
999
1000 /**********************************************************************
1001  *          IsSharedSelector    (KERNEL.345)
1002  */
1003 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
1004 {
1005     /* Check whether the selector belongs to a DLL */
1006     NE_MODULE *pModule = NE_GetPtr( selector );
1007     if (!pModule) return FALSE;
1008     return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;
1009 }