Avoid HeapReAlloc of a NULL pointer.
[wine] / dlls / kernel / 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 "wownt32.h"
38 #include "wine/library.h"
39 #include "global.h"
40 #include "task.h"
41 #include "file.h"
42 #include "module.h"
43 #include "stackframe.h"
44 #include "builtin16.h"
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(fixup);
48 WINE_DECLARE_DEBUG_CHANNEL(dll);
49 WINE_DECLARE_DEBUG_CHANNEL(module);
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
87 /***********************************************************************
88  *           NE_GetRelocAddrName
89  */
90 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
91 {
92     switch(addr_type & 0x7f)
93     {
94     case NE_RADDR_LOWBYTE:   return additive ? "BYTE add" : "BYTE";
95     case NE_RADDR_OFFSET16:  return additive ? "OFFSET16 add" : "OFFSET16";
96     case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
97     case NE_RADDR_SELECTOR:  return additive ? "SELECTOR add" : "SELECTOR";
98     case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
99     case NE_RADDR_OFFSET32:  return additive ? "OFFSET32 add" : "OFFSET32";
100     }
101     return "???";
102 }
103
104
105 /***********************************************************************
106  *           NE_LoadSegment
107  */
108 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
109 {
110     SEGTABLEENTRY *pSegTable, *pSeg;
111     WORD *pModuleTable;
112     WORD count, i, offset, next_offset;
113     HMODULE16 module;
114     FARPROC16 address = 0;
115     HANDLE hf;
116     DWORD res;
117     struct relocation_entry_s *rep, *reloc_entries;
118     BYTE *func_name;
119     int size;
120     char* mem;
121
122     char buffer[256];
123     int ordinal, additive;
124     unsigned short *sp;
125
126     pSegTable = NE_SEG_TABLE( pModule );
127     pSeg = pSegTable + segnum - 1;
128
129     if (pSeg->flags & NE_SEGFLAGS_LOADED)
130     {
131         /* self-loader ? -> already loaded it */
132         if (pModule->flags & NE_FFLAGS_SELFLOAD)
133             return TRUE;
134
135         /* leave, except for DGROUP, as this may be the second instance */
136         if (segnum != pModule->dgroup)
137             return TRUE;
138     }
139
140     if (!pSeg->filepos) return TRUE;  /* No file image, just return */
141
142     pModuleTable = NE_MODULE_TABLE( pModule );
143
144     hf = NE_OpenFile( pModule );
145     TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
146                     segnum, pSeg->hSeg, pSeg->flags );
147     SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
148     if (pSeg->size) size = pSeg->size;
149     else size = pSeg->minsize ? pSeg->minsize : 0x10000;
150     mem = GlobalLock16(pSeg->hSeg);
151     if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
152     {
153         /* Implement self-loading segments */
154         SELFLOADHEADER *selfloadheader;
155         DWORD oldstack;
156         HANDLE hFile32;
157         HFILE16 hFile16;
158         WORD args[3];
159         DWORD ret;
160
161         selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
162         oldstack = NtCurrentTeb()->cur_stack;
163         NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
164                                                0xff00 - sizeof(STACK16FRAME));
165
166         TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=%p,segnum=%d\n",
167                 pModule->self,hf,segnum );
168         DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
169                          0, FALSE, DUPLICATE_SAME_ACCESS );
170         hFile16 = Win32HandleToDosFileHandle( hFile32 );
171         args[2] = pModule->self;
172         args[1] = hFile16;
173         args[0] = segnum;
174         WOWCallback16Ex( (DWORD)selfloadheader->LoadAppSeg, WCB16_PASCAL, sizeof(args), args, &ret );
175         pSeg->hSeg = LOWORD(ret);
176         TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
177         _lclose16( hFile16 );
178         NtCurrentTeb()->cur_stack = oldstack;
179     }
180     else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
181         ReadFile(hf, mem, size, &res, NULL);
182     else {
183       /*
184          The following bit of code for "iterated segments" was written without
185          any documentation on the format of these segments. It seems to work,
186          but may be missing something. If you have any doc please either send
187          it to me or fix the code yourself. gfm@werple.mira.net.au
188       */
189       char* buff = HeapAlloc(GetProcessHeap(), 0, size);
190       char* curr = buff;
191
192       if(buff == NULL) {
193           WARN_(dll)("Memory exausted!");
194           goto fail;
195       }
196
197       ReadFile(hf, buff, size, &res, NULL);
198       while(curr < buff + size) {
199         unsigned int rept = *((short*) curr)++;
200         unsigned int len = *((short*) curr)++;
201         for(; rept > 0; rept--) {
202           char* bytes = curr;
203           unsigned int byte;
204           for(byte = 0; byte < len; byte++)
205             *mem++ = *bytes++;
206         }
207         curr += len;
208       }
209       HeapFree(GetProcessHeap(), 0, buff);
210     }
211
212     pSeg->flags |= NE_SEGFLAGS_LOADED;
213
214     /* Perform exported function prolog fixups */
215     NE_FixupSegmentPrologs( pModule, segnum );
216
217     if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
218         goto succeed;  /* No relocation data, we are done */
219
220     ReadFile(hf, &count, sizeof(count), &res, NULL);
221     if (!count) goto succeed;
222
223     TRACE("Fixups for %.*s, segment %d, hSeg %04x\n",
224                    *((BYTE *)pModule + pModule->name_table),
225                    (char *)pModule + pModule->name_table + 1,
226                    segnum, pSeg->hSeg );
227
228     reloc_entries = (struct relocation_entry_s *)HeapAlloc(GetProcessHeap(), 0, count * sizeof(struct relocation_entry_s));
229     if(reloc_entries == NULL) {
230         WARN("Not enough memory for relocation entries!");
231         goto fail;
232     }
233     if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
234         (res != count * sizeof(struct relocation_entry_s)))
235     {
236         WARN("Unable to read relocation information\n" );
237         goto fail;
238     }
239
240     /*
241      * Go through the relocation table one entry at a time.
242      */
243     rep = reloc_entries;
244     for (i = 0; i < count; i++, rep++)
245     {
246         /*
247          * Get the target address corresponding to this entry.
248          */
249
250         /* If additive, there is no target chain list. Instead, add source
251            and target */
252         additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
253         rep->relocation_type &= 0x3;
254
255         switch (rep->relocation_type)
256         {
257           case NE_RELTYPE_ORDINAL:
258             module = pModuleTable[rep->target1-1];
259             ordinal = rep->target2;
260             address = NE_GetEntryPoint( module, ordinal );
261             if (!address)
262             {
263                 NE_MODULE *pTarget = NE_GetPtr( module );
264                 if (!pTarget)
265                     WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
266                              module, rep->target1,
267                              *((BYTE *)pModule + pModule->name_table),
268                              *((BYTE *)pModule + pModule->name_table),
269                              (char *)pModule + pModule->name_table + 1 );
270                 else
271                 {
272                     ERR("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
273                             *((BYTE *)pTarget + pTarget->name_table),
274                             (char *)pTarget + pTarget->name_table + 1,
275                             ordinal );
276                     address = (FARPROC16)0xdeadbeef;
277                 }
278             }
279             if (TRACE_ON(fixup))
280             {
281                 NE_MODULE *pTarget = NE_GetPtr( module );
282                 TRACE("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
283                        *((BYTE *)pTarget + pTarget->name_table),
284                        (char *)pTarget + pTarget->name_table + 1,
285                        ordinal, HIWORD(address), LOWORD(address),
286                        NE_GetRelocAddrName( rep->address_type, additive ) );
287             }
288             break;
289
290           case NE_RELTYPE_NAME:
291             module = pModuleTable[rep->target1-1];
292             func_name = (char *)pModule + pModule->import_table + rep->target2;
293             memcpy( buffer, func_name+1, *func_name );
294             buffer[*func_name] = '\0';
295             func_name = buffer;
296             ordinal = NE_GetOrdinal( module, func_name );
297             address = NE_GetEntryPoint( module, ordinal );
298
299             if (ERR_ON(fixup) && !address)
300             {
301                 NE_MODULE *pTarget = NE_GetPtr( module );
302                 ERR("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
303                     *((BYTE *)pTarget + pTarget->name_table),
304                     (char *)pTarget + pTarget->name_table + 1, func_name );
305             }
306             if (!address) address = (FARPROC16) 0xdeadbeef;
307             if (TRACE_ON(fixup))
308             {
309                 NE_MODULE *pTarget = NE_GetPtr( module );
310                 TRACE("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
311                        *((BYTE *)pTarget + pTarget->name_table),
312                        (char *)pTarget + pTarget->name_table + 1,
313                        func_name, HIWORD(address), LOWORD(address),
314                        NE_GetRelocAddrName( rep->address_type, additive ) );
315             }
316             break;
317
318           case NE_RELTYPE_INTERNAL:
319             if ((rep->target1 & 0xff) == 0xff)
320             {
321                 address  = NE_GetEntryPoint( pModule->self, rep->target2 );
322             }
323             else
324             {
325                 address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
326             }
327
328             TRACE("%d: %04x:%04x %s\n",
329                    i + 1, HIWORD(address), LOWORD(address),
330                    NE_GetRelocAddrName( rep->address_type, additive ) );
331             break;
332
333           case NE_RELTYPE_OSFIXUP:
334             /* Relocation type 7:
335              *
336              *    These appear to be used as fixups for the Windows
337              * floating point emulator.  Let's just ignore them and
338              * try to use the hardware floating point.  Linux should
339              * successfully emulate the coprocessor if it doesn't
340              * exist.
341              */
342             TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
343                    i + 1, rep->relocation_type, rep->offset,
344                    rep->target1, rep->target2,
345                    NE_GetRelocAddrName( rep->address_type, additive ) );
346             continue;
347         }
348
349         offset  = rep->offset;
350
351         /* Apparently, high bit of address_type is sometimes set; */
352         /* we ignore it for now */
353         if (rep->address_type > NE_RADDR_OFFSET32)
354         {
355             char module[10];
356             GetModuleName16( pModule->self, module, sizeof(module) );
357             ERR("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
358                  module, rep->address_type );
359         }
360
361         if (additive)
362         {
363             sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
364             TRACE("    %04x:%04x\n", offset, *sp );
365             switch (rep->address_type & 0x7f)
366             {
367             case NE_RADDR_LOWBYTE:
368                 *(BYTE *)sp += LOBYTE((int)address);
369                 break;
370             case NE_RADDR_OFFSET16:
371                 *sp += LOWORD(address);
372                 break;
373             case NE_RADDR_POINTER32:
374                 *sp += LOWORD(address);
375                 *(sp+1) = HIWORD(address);
376                 break;
377             case NE_RADDR_SELECTOR:
378                 /* Borland creates additive records with offset zero. Strange, but OK */
379                 if (*sp)
380                     ERR("Additive selector to %04x.Please report\n",*sp);
381                 else
382                     *sp = HIWORD(address);
383                 break;
384             default:
385                 goto unknown;
386             }
387         }
388         else  /* non-additive fixup */
389         {
390             do
391             {
392                 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
393                 next_offset = *sp;
394                 TRACE("    %04x:%04x\n", offset, *sp );
395                 switch (rep->address_type & 0x7f)
396                 {
397                 case NE_RADDR_LOWBYTE:
398                     *(BYTE *)sp = LOBYTE((int)address);
399                     break;
400                 case NE_RADDR_OFFSET16:
401                     *sp = LOWORD(address);
402                     break;
403                 case NE_RADDR_POINTER32:
404                     *(FARPROC16 *)sp = address;
405                     break;
406                 case NE_RADDR_SELECTOR:
407                     *sp = SELECTOROF(address);
408                     break;
409                 default:
410                     goto unknown;
411                 }
412                 if (next_offset == offset) break;  /* avoid infinite loop */
413                 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
414                 offset = next_offset;
415             } while (offset != 0xffff);
416         }
417     }
418
419     HeapFree(GetProcessHeap(), 0, reloc_entries);
420
421 succeed:
422     CloseHandle(hf);
423     return TRUE;
424
425 unknown:
426     WARN("WARNING: %d: unknown ADDR TYPE %d,  "
427          "TYPE %d,  OFFSET %04x,  TARGET %04x %04x\n",
428          i + 1, rep->address_type, rep->relocation_type,
429          rep->offset, rep->target1, rep->target2);
430     HeapFree(GetProcessHeap(), 0, reloc_entries);
431
432 fail:
433     CloseHandle(hf);
434     return FALSE;
435 }
436
437
438 /***********************************************************************
439  *           NE_LoadAllSegments
440  */
441 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
442 {
443     int i;
444     SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
445
446     if (pModule->flags & NE_FFLAGS_SELFLOAD)
447     {
448         HANDLE hf;
449         HFILE16 hFile16;
450         HGLOBAL16 sel;
451         /* Handle self-loading modules */
452         SELFLOADHEADER *selfloadheader;
453         HMODULE16 mod = GetModuleHandle16("KERNEL");
454         DWORD oldstack;
455         WORD args[2];
456
457         TRACE_(module)("%.*s is a self-loading module!\n",
458                      *((BYTE*)pModule + pModule->name_table),
459                      (char *)pModule + pModule->name_table + 1);
460         if (!NE_LoadSegment( pModule, 1 )) return FALSE;
461         selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) );
462         selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc");
463         selfloadheader->MyAlloc       = GetProcAddress16(mod,"MyAlloc");
464         selfloadheader->SetOwner      = GetProcAddress16(mod,"FarSetOwner");
465         sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 );
466         pModule->self_loading_sel = SEL(sel);
467         FarSetOwner16( sel, pModule->self );
468         oldstack = NtCurrentTeb()->cur_stack;
469         NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
470                                                0xff00 - sizeof(STACK16FRAME) );
471
472         hf = NE_OpenFile(pModule);
473         hFile16 = Win32HandleToDosFileHandle( hf );
474         TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
475               pModule->self,hFile16);
476         args[1] = pModule->self;
477         args[0] = hFile16;
478         WOWCallback16Ex( (DWORD)selfloadheader->BootApp, WCB16_PASCAL, sizeof(args), args, NULL );
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("(%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("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("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("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("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("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("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     NE_CallUserSignalProc( pModule->self, USIG16_DLL_LOAD );
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     WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)&context );
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_CallUserSignalProc
719  *
720  * According to "Undocumented Windows", the task signal proc is
721  * bypassed for module load/unload notifications, and the USER signal
722  * proc is called directly instead. This is what this function does.
723  */
724 typedef DWORD (WINAPI *pSignalProc)( HANDLE16 module, UINT16 code, UINT16 exit,
725                                      HINSTANCE16 inst, HQUEUE16 queue );
726
727 void NE_CallUserSignalProc( HMODULE16 hModule, UINT16 code )
728 {
729     FARPROC16 proc;
730     HMODULE16 user = GetModuleHandle16("user.exe");
731
732     if (!user) return;
733     if ((proc = GetProcAddress16( user, "SignalProc" )))
734     {
735         /* USER is always a builtin dll */
736         pSignalProc sigproc = (pSignalProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)proc ))->target;
737         sigproc( hModule, code, 0, 0, 0 );
738     }
739 }
740
741
742 /***********************************************************************
743  *           NE_CallDllEntryPoint
744  *
745  * Call the DllEntryPoint of DLLs with subsystem >= 4.0
746  */
747 typedef DWORD (WINAPI *WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
748
749 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
750 {
751     WORD hInst, ds, heap;
752     FARPROC16 entryPoint;
753
754     if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) return;
755     if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
756     if (!(entryPoint = GetProcAddress16( pModule->self, "DllEntryPoint" ))) return;
757
758     NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
759
760     TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
761                  NE_MODULE_NAME( pModule ),
762                  SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
763
764     if ( pModule->flags & NE_FFLAGS_BUILTIN )
765     {
766         WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target;
767
768         entryProc( dwReason, hInst, ds, heap, 0, 0 );
769     }
770     else
771     {
772         CONTEXT86 context;
773         WORD args[8];
774
775         memset( &context, 0, sizeof(context) );
776         context.SegDs = ds;
777         context.SegEs = ds;   /* who knows ... */
778
779         context.SegCs = HIWORD(entryPoint);
780         context.Eip = LOWORD(entryPoint);
781         context.Ebp =  OFFSETOF( NtCurrentTeb()->cur_stack )
782                              + (WORD)&((STACK16FRAME*)0)->bp;
783
784         args[7] = HIWORD(dwReason);
785         args[6] = LOWORD(dwReason);
786         args[5] = hInst;
787         args[4] = ds;
788         args[3] = heap;
789         args[2] = 0;     /* HIWORD(dwReserved1) */
790         args[1] = 0;     /* LOWORD(dwReserved1) */
791         args[0] = 0;     /* wReserved2 */
792         WOWCallback16Ex( 0, WCB16_REGS, sizeof(args), args, (DWORD *)&context );
793     }
794 }
795
796 /***********************************************************************
797  *           NE_DllProcessAttach
798  *
799  * Call the DllEntryPoint of all modules this one (recursively)
800  * depends on, according to the order in which they were loaded.
801  *
802  * Note that --as opposed to the PE module case-- there is no notion
803  * of 'module loaded into a process' for NE modules, and hence we
804  * have no place to store the fact that the DllEntryPoint of a
805  * given module was already called on behalf of this process (e.g.
806  * due to some earlier LoadLibrary16 call).
807  *
808  * Thus, we just call the DllEntryPoint twice in that case.  Win9x
809  * appears to behave this way as well ...
810  *
811  * This routine must only be called with the Win16Lock held.
812  *
813  * FIXME:  We should actually abort loading in case the DllEntryPoint
814  *         returns FALSE ...
815  *
816  */
817
818 struct ne_init_list
819 {
820     int count;
821     int size;
822     NE_MODULE **module;
823 };
824
825 static void add_to_init_list( struct ne_init_list *list, NE_MODULE *hModule )
826 {
827     NE_MODULE **newModule = NULL;
828     if ( list->count == list->size )
829     {
830         int newSize = list->size + 128;
831
832         if (list->module) 
833             newModule = HeapReAlloc( GetProcessHeap(), 0,
834                                              list->module, newSize*sizeof(NE_MODULE *) );
835         else
836             newModule = HeapAlloc( GetProcessHeap(), 0,
837                                              newSize*sizeof(NE_MODULE *) );
838         if ( !newModule )
839         {
840             FIXME_(dll)("Out of memory!");
841             return;
842         }
843
844         list->module = newModule;
845         list->size   = newSize;
846     }
847
848     list->module[list->count++] = hModule;
849 }
850
851 static void free_init_list( struct ne_init_list *list )
852 {
853     if ( list->module )
854     {
855         HeapFree( GetProcessHeap(), 0, list->module );
856         memset( list, 0, sizeof(*list) );
857     }
858 }
859
860 static void fill_init_list( struct ne_init_list *list, HMODULE16 hModule )
861 {
862     NE_MODULE *pModule;
863     WORD *pModRef;
864     int i;
865
866     if (!(pModule = NE_GetPtr( hModule ))) return;
867     assert( !(pModule->flags & NE_FFLAGS_WIN32) );
868
869     /* Never add a module twice */
870     for ( i = 0; i < list->count; i++ )
871         if ( list->module[i] == pModule )
872             return;
873
874     /* Check for recursive call */
875     if ( pModule->misc_flags & 0x80 ) return;
876
877     TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
878
879     /* Tag current module to prevent recursive loop */
880     pModule->misc_flags |= 0x80;
881
882     /* Recursively attach all DLLs this one depends on */
883     pModRef = NE_MODULE_TABLE( pModule );
884     for ( i = 0; i < pModule->modref_count; i++ )
885         if ( pModRef[i] )
886             fill_init_list( list, (HMODULE16)pModRef[i] );
887
888     /* Add current module */
889     add_to_init_list( list, pModule );
890
891     /* Remove recursion flag */
892     pModule->misc_flags &= ~0x80;
893
894     TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
895 }
896
897 static void call_init_list( struct ne_init_list *list )
898 {
899     int i;
900     for ( i = 0; i < list->count; i++ )
901         NE_CallDllEntryPoint( list->module[i], DLL_PROCESS_ATTACH );
902 }
903
904 void NE_DllProcessAttach( HMODULE16 hModule )
905 {
906     struct ne_init_list list;
907     memset( &list, 0, sizeof(list) );
908
909     fill_init_list( &list, hModule );
910     call_init_list( &list );
911     free_init_list( &list );
912 }
913
914
915 /***********************************************************************
916  *           NE_Ne2MemFlags
917  *
918  * This function translates NE segment flags to GlobalAlloc flags
919  */
920 static WORD NE_Ne2MemFlags(WORD flags)
921 {
922     WORD memflags = 0;
923 #if 1
924     if (flags & NE_SEGFLAGS_DISCARDABLE)
925       memflags |= GMEM_DISCARDABLE;
926     if (flags & NE_SEGFLAGS_MOVEABLE ||
927         ( ! (flags & NE_SEGFLAGS_DATA) &&
928           ! (flags & NE_SEGFLAGS_LOADED) &&
929           ! (flags & NE_SEGFLAGS_ALLOCATED)
930          )
931         )
932       memflags |= GMEM_MOVEABLE;
933     memflags |= GMEM_ZEROINIT;
934 #else
935     memflags = GMEM_ZEROINIT | GMEM_FIXED;
936 #endif
937     return memflags;
938 }
939
940 /***********************************************************************
941  *           MyAlloc   (KERNEL.668) Wine-specific export
942  *
943  * MyAlloc() function for self-loading apps.
944  */
945 DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
946 {
947     WORD size = wSize << wElem;
948     HANDLE16 hMem = 0;
949
950     if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
951         hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
952
953     if ( ((wFlags & 0x7) != 0x1) && /* DATA */
954          ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
955     {
956         WORD hSel = SEL(hMem);
957         WORD access = SelectorAccessRights16(hSel,0,0);
958
959         access |= 2<<2; /* SEGMENT_CODE */
960         SelectorAccessRights16(hSel,1,access);
961     }
962     if (size)
963         return MAKELONG( hMem, SEL(hMem) );
964     else
965         return MAKELONG( 0, hMem );
966 }
967
968 /***********************************************************************
969  *           NE_GetInstance
970  */
971 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
972 {
973     if ( !pModule->dgroup )
974         return pModule->self;
975     else
976     {
977         SEGTABLEENTRY *pSeg;
978         pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
979         return pSeg->hSeg;
980     }
981 }
982
983 /***********************************************************************
984  *           NE_CreateSegment
985  */
986 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
987 {
988     SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
989     int minsize;
990     unsigned char selflags;
991
992     assert( !(pModule->flags & NE_FFLAGS_WIN32) );
993
994     if ( segnum < 1 || segnum > pModule->seg_count )
995         return FALSE;
996
997     if ( (pModule->flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
998         return TRUE;    /* selfloader allocates segment itself */
999
1000     if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->dgroup )
1001         return TRUE;    /* all but DGROUP only allocated once */
1002
1003     minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
1004     if ( segnum == pModule->ss )     minsize += pModule->stack_size;
1005     if ( segnum == pModule->dgroup ) minsize += pModule->heap_size;
1006
1007     selflags = (pSeg->flags & NE_SEGFLAGS_DATA) ? WINE_LDT_FLAGS_DATA : WINE_LDT_FLAGS_CODE;
1008     if (pSeg->flags & NE_SEGFLAGS_32BIT) selflags |= WINE_LDT_FLAGS_32BIT;
1009     pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags), minsize, pModule->self, selflags );
1010     if (!pSeg->hSeg) return FALSE;
1011
1012     pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
1013     return TRUE;
1014 }
1015
1016 /***********************************************************************
1017  *           NE_CreateAllSegments
1018  */
1019 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
1020 {
1021     int i;
1022     for ( i = 1; i <= pModule->seg_count; i++ )
1023         if ( !NE_CreateSegment( pModule, i ) )
1024             return FALSE;
1025
1026     pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
1027                             (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
1028     return TRUE;
1029 }
1030
1031
1032 /**********************************************************************
1033  *          IsSharedSelector    (KERNEL.345)
1034  */
1035 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
1036 {
1037     /* Check whether the selector belongs to a DLL */
1038     NE_MODULE *pModule = NE_GetPtr( selector );
1039     if (!pModule) return FALSE;
1040     return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;
1041 }