Fixed the LARGE_INTEGER and ULARGE_INTEGER unions for big endian.
[wine/wine-gecko.git] / loader / ne / segment.c
blobc0e0af9eab55160074921a1ee64d809480d8b703
1 /*
2 * NE segment loading
4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
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.
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.
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
22 #include <assert.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <ctype.h>
29 #include <string.h>
31 #include "wine/winbase16.h"
32 #include "wine/library.h"
33 #include "global.h"
34 #include "task.h"
35 #include "file.h"
36 #include "module.h"
37 #include "stackframe.h"
38 #include "builtin16.h"
39 #include "wine/debug.h"
41 WINE_DECLARE_DEBUG_CHANNEL(dll);
42 WINE_DECLARE_DEBUG_CHANNEL(fixup);
43 WINE_DECLARE_DEBUG_CHANNEL(module);
44 WINE_DECLARE_DEBUG_CHANNEL(segment);
47 * Relocation table entry
49 struct relocation_entry_s
51 BYTE address_type; /* Relocation address type */
52 BYTE relocation_type; /* Relocation type */
53 WORD offset; /* Offset in segment to fixup */
54 WORD target1; /* Target specification */
55 WORD target2; /* Target specification */
59 * Relocation address types
61 #define NE_RADDR_LOWBYTE 0
62 #define NE_RADDR_SELECTOR 2
63 #define NE_RADDR_POINTER32 3
64 #define NE_RADDR_OFFSET16 5
65 #define NE_RADDR_POINTER48 11
66 #define NE_RADDR_OFFSET32 13
69 * Relocation types
71 #define NE_RELTYPE_INTERNAL 0
72 #define NE_RELTYPE_ORDINAL 1
73 #define NE_RELTYPE_NAME 2
74 #define NE_RELTYPE_OSFIXUP 3
75 #define NE_RELFLAG_ADDITIVE 4
77 #define SEL(x) ((x)|1)
79 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);
81 /* ### start build ### */
82 extern WORD CALLBACK NE_CallTo16_word_ww(FARPROC16,WORD,WORD);
83 extern WORD CALLBACK NE_CallTo16_word_www(FARPROC16,WORD,WORD,WORD);
84 /* ### stop build ### */
86 /***********************************************************************
87 * NE_GetRelocAddrName
89 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
91 switch(addr_type & 0x7f)
93 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
94 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
95 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
96 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
97 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
98 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
100 return "???";
104 /***********************************************************************
105 * NE_LoadSegment
107 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
109 SEGTABLEENTRY *pSegTable, *pSeg;
110 WORD *pModuleTable;
111 WORD count, i, offset, next_offset;
112 HMODULE16 module;
113 FARPROC16 address = 0;
114 HFILE hf;
115 DWORD res;
116 struct relocation_entry_s *rep, *reloc_entries;
117 BYTE *func_name;
118 int size;
119 char* mem;
121 char buffer[256];
122 int ordinal, additive;
123 unsigned short *sp;
125 pSegTable = NE_SEG_TABLE( pModule );
126 pSeg = pSegTable + segnum - 1;
128 if (pSeg->flags & NE_SEGFLAGS_LOADED)
130 /* self-loader ? -> already loaded it */
131 if (pModule->flags & NE_FFLAGS_SELFLOAD)
132 return TRUE;
134 /* leave, except for DGROUP, as this may be the second instance */
135 if (segnum != pModule->dgroup)
136 return TRUE;
139 if (!pSeg->filepos) return TRUE; /* No file image, just return */
141 pModuleTable = NE_MODULE_TABLE( pModule );
143 hf = NE_OpenFile( pModule );
144 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
145 segnum, pSeg->hSeg, pSeg->flags );
146 SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
147 if (pSeg->size) size = pSeg->size;
148 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
149 mem = GlobalLock16(pSeg->hSeg);
150 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
152 /* Implement self-loading segments */
153 SELFLOADHEADER *selfloadheader;
154 DWORD oldstack;
155 HFILE hFile32;
156 HFILE16 hFile16;
158 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
159 oldstack = NtCurrentTeb()->cur_stack;
160 NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
161 0xff00 - sizeof(STACK16FRAME));
163 TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
164 pModule->self,hf,segnum );
165 DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
166 0, FALSE, DUPLICATE_SAME_ACCESS );
167 hFile16 = Win32HandleToDosFileHandle( hFile32 );
168 pSeg->hSeg = NE_CallTo16_word_www( selfloadheader->LoadAppSeg,
169 pModule->self, hFile16, segnum );
170 TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
171 _lclose16( hFile16 );
172 NtCurrentTeb()->cur_stack = oldstack;
174 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
175 ReadFile(hf, mem, size, &res, NULL);
176 else {
178 The following bit of code for "iterated segments" was written without
179 any documentation on the format of these segments. It seems to work,
180 but may be missing something. If you have any doc please either send
181 it to me or fix the code yourself. gfm@werple.mira.net.au
183 char* buff = HeapAlloc(GetProcessHeap(), 0, size);
184 char* curr = buff;
186 if(buff == NULL) {
187 WARN_(dll)("Memory exausted!");
188 return FALSE;
191 ReadFile(hf, buff, size, &res, NULL);
192 while(curr < buff + size) {
193 unsigned int rept = *((short*) curr)++;
194 unsigned int len = *((short*) curr)++;
195 for(; rept > 0; rept--) {
196 char* bytes = curr;
197 unsigned int byte;
198 for(byte = 0; byte < len; byte++)
199 *mem++ = *bytes++;
201 curr += len;
203 HeapFree(GetProcessHeap(), 0, buff);
206 pSeg->flags |= NE_SEGFLAGS_LOADED;
208 /* Perform exported function prolog fixups */
209 NE_FixupSegmentPrologs( pModule, segnum );
211 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
212 return TRUE; /* No relocation data, we are done */
214 ReadFile(hf, &count, sizeof(count), &res, NULL);
215 if (!count) return TRUE;
217 TRACE_(fixup)("Fixups for %.*s, segment %d, hSeg %04x\n",
218 *((BYTE *)pModule + pModule->name_table),
219 (char *)pModule + pModule->name_table + 1,
220 segnum, pSeg->hSeg );
221 TRACE_(segment)("Fixups for %.*s, segment %d, hSeg %04x\n",
222 *((BYTE *)pModule + pModule->name_table),
223 (char *)pModule + pModule->name_table + 1,
224 segnum, pSeg->hSeg );
226 reloc_entries = (struct relocation_entry_s *)HeapAlloc(GetProcessHeap(), 0, count * sizeof(struct relocation_entry_s));
227 if(reloc_entries == NULL) {
228 WARN_(fixup)("Not enough memory for relocation entries!");
229 return FALSE;
231 if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
232 (res != count * sizeof(struct relocation_entry_s)))
234 WARN_(fixup)("Unable to read relocation information\n" );
235 return FALSE;
239 * Go through the relocation table one entry at a time.
241 rep = reloc_entries;
242 for (i = 0; i < count; i++, rep++)
245 * Get the target address corresponding to this entry.
248 /* If additive, there is no target chain list. Instead, add source
249 and target */
250 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
251 rep->relocation_type &= 0x3;
253 switch (rep->relocation_type)
255 case NE_RELTYPE_ORDINAL:
256 module = pModuleTable[rep->target1-1];
257 ordinal = rep->target2;
258 address = NE_GetEntryPoint( module, ordinal );
259 if (!address)
261 NE_MODULE *pTarget = NE_GetPtr( module );
262 if (!pTarget)
263 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
264 module, rep->target1,
265 *((BYTE *)pModule + pModule->name_table),
266 *((BYTE *)pModule + pModule->name_table),
267 (char *)pModule + pModule->name_table + 1 );
268 else
270 ERR_(fixup)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
271 *((BYTE *)pTarget + pTarget->name_table),
272 (char *)pTarget + pTarget->name_table + 1,
273 ordinal );
274 address = (FARPROC16)0xdeadbeef;
277 if (TRACE_ON(fixup))
279 NE_MODULE *pTarget = NE_GetPtr( module );
280 TRACE_(fixup)("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
281 *((BYTE *)pTarget + pTarget->name_table),
282 (char *)pTarget + pTarget->name_table + 1,
283 ordinal, HIWORD(address), LOWORD(address),
284 NE_GetRelocAddrName( rep->address_type, additive ) );
286 break;
288 case NE_RELTYPE_NAME:
289 module = pModuleTable[rep->target1-1];
290 func_name = (char *)pModule + pModule->import_table + rep->target2;
291 memcpy( buffer, func_name+1, *func_name );
292 buffer[*func_name] = '\0';
293 func_name = buffer;
294 ordinal = NE_GetOrdinal( module, func_name );
295 address = NE_GetEntryPoint( module, ordinal );
297 if (ERR_ON(fixup) && !address)
299 NE_MODULE *pTarget = NE_GetPtr( module );
300 ERR_(fixup)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
301 *((BYTE *)pTarget + pTarget->name_table),
302 (char *)pTarget + pTarget->name_table + 1, func_name );
304 if (!address) address = (FARPROC16) 0xdeadbeef;
305 if (TRACE_ON(fixup))
307 NE_MODULE *pTarget = NE_GetPtr( module );
308 TRACE_(fixup)("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
309 *((BYTE *)pTarget + pTarget->name_table),
310 (char *)pTarget + pTarget->name_table + 1,
311 func_name, HIWORD(address), LOWORD(address),
312 NE_GetRelocAddrName( rep->address_type, additive ) );
314 break;
316 case NE_RELTYPE_INTERNAL:
317 if ((rep->target1 & 0xff) == 0xff)
319 address = NE_GetEntryPoint( pModule->self, rep->target2 );
321 else
323 address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
326 TRACE_(fixup)("%d: %04x:%04x %s\n",
327 i + 1, HIWORD(address), LOWORD(address),
328 NE_GetRelocAddrName( rep->address_type, additive ) );
329 break;
331 case NE_RELTYPE_OSFIXUP:
332 /* Relocation type 7:
334 * These appear to be used as fixups for the Windows
335 * floating point emulator. Let's just ignore them and
336 * try to use the hardware floating point. Linux should
337 * successfully emulate the coprocessor if it doesn't
338 * exist.
340 TRACE_(fixup)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
341 i + 1, rep->relocation_type, rep->offset,
342 rep->target1, rep->target2,
343 NE_GetRelocAddrName( rep->address_type, additive ) );
344 continue;
347 offset = rep->offset;
349 /* Apparently, high bit of address_type is sometimes set; */
350 /* we ignore it for now */
351 if (rep->address_type > NE_RADDR_OFFSET32)
353 char module[10];
354 GetModuleName16( pModule->self, module, sizeof(module) );
355 ERR_(fixup)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
356 module, rep->address_type );
359 if (additive)
361 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
362 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
363 switch (rep->address_type & 0x7f)
365 case NE_RADDR_LOWBYTE:
366 *(BYTE *)sp += LOBYTE((int)address);
367 break;
368 case NE_RADDR_OFFSET16:
369 *sp += LOWORD(address);
370 break;
371 case NE_RADDR_POINTER32:
372 *sp += LOWORD(address);
373 *(sp+1) = HIWORD(address);
374 break;
375 case NE_RADDR_SELECTOR:
376 /* Borland creates additive records with offset zero. Strange, but OK */
377 if (*sp)
378 ERR_(fixup)("Additive selector to %04x.Please report\n",*sp);
379 else
380 *sp = HIWORD(address);
381 break;
382 default:
383 goto unknown;
386 else /* non-additive fixup */
390 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
391 next_offset = *sp;
392 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
393 switch (rep->address_type & 0x7f)
395 case NE_RADDR_LOWBYTE:
396 *(BYTE *)sp = LOBYTE((int)address);
397 break;
398 case NE_RADDR_OFFSET16:
399 *sp = LOWORD(address);
400 break;
401 case NE_RADDR_POINTER32:
402 *(FARPROC16 *)sp = address;
403 break;
404 case NE_RADDR_SELECTOR:
405 *sp = SELECTOROF(address);
406 break;
407 default:
408 goto unknown;
410 if (next_offset == offset) break; /* avoid infinite loop */
411 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
412 offset = next_offset;
413 } while (offset != 0xffff);
417 HeapFree(GetProcessHeap(), 0, reloc_entries);
418 return TRUE;
420 unknown:
421 WARN_(fixup)("WARNING: %d: unknown ADDR TYPE %d, "
422 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
423 i + 1, rep->address_type, rep->relocation_type,
424 rep->offset, rep->target1, rep->target2);
425 HeapFree(GetProcessHeap(), 0, reloc_entries);
426 return FALSE;
430 /***********************************************************************
431 * NE_LoadAllSegments
433 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
435 int i;
436 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
438 if (pModule->flags & NE_FFLAGS_SELFLOAD)
440 HFILE hf;
441 HFILE16 hFile16;
442 HGLOBAL16 sel;
443 /* Handle self-loading modules */
444 SELFLOADHEADER *selfloadheader;
445 HMODULE16 mod = GetModuleHandle16("KERNEL");
446 DWORD oldstack;
448 TRACE_(module)("%.*s is a self-loading module!\n",
449 *((BYTE*)pModule + pModule->name_table),
450 (char *)pModule + pModule->name_table + 1);
451 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
452 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) );
453 selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc");
454 selfloadheader->MyAlloc = GetProcAddress16(mod,"MyAlloc");
455 selfloadheader->SetOwner = GetProcAddress16(mod,"FarSetOwner");
456 sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 );
457 pModule->self_loading_sel = SEL(sel);
458 FarSetOwner16( sel, pModule->self );
459 oldstack = NtCurrentTeb()->cur_stack;
460 NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
461 0xff00 - sizeof(STACK16FRAME) );
463 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule),
464 GetCurrentProcess(), &hf, 0, FALSE, DUPLICATE_SAME_ACCESS );
465 hFile16 = Win32HandleToDosFileHandle( hf );
466 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
467 pModule->self,hFile16);
468 NE_CallTo16_word_ww(selfloadheader->BootApp, pModule->self,hFile16);
469 TRACE_(dll)("Return from CallBootAppProc\n");
470 _lclose16(hFile16);
471 NtCurrentTeb()->cur_stack = oldstack;
473 for (i = 2; i <= pModule->seg_count; i++)
474 if (!NE_LoadSegment( pModule, i )) return FALSE;
476 else
478 for (i = 1; i <= pModule->seg_count; i++)
479 if (!NE_LoadSegment( pModule, i )) return FALSE;
481 return TRUE;
485 /***********************************************************************
486 * NE_FixupSegmentPrologs
488 * Fixup exported functions prologs of one segment
490 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
492 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
493 ET_BUNDLE *bundle;
494 ET_ENTRY *entry;
495 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
496 BYTE *pSeg, *pFunc;
498 TRACE_(module)("(%d);\n", segnum);
500 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
502 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
503 return;
506 if (!pModule->dgroup) return;
508 if (!(dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg))) return;
510 pSeg = MapSL( MAKESEGPTR(sel, 0) );
512 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);
514 do {
515 TRACE_(module)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
516 if (!(num_entries = bundle->last - bundle->first))
517 return;
518 entry = (ET_ENTRY *)((BYTE *)bundle+6);
519 while (num_entries--)
521 /*TRACE_(module)("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
522 if (entry->segnum == segnum)
524 pFunc = ((BYTE *)pSeg+entry->offs);
525 TRACE_(module)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
526 if (*(pFunc+2) == 0x90)
528 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
530 TRACE_(module)("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
531 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
534 if (*(WORD *)pFunc == 0xd88c)
536 if ((entry->flags & 2)) /* public data ? */
538 TRACE_(module)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
539 *pFunc = 0xb8; /* mov ax, */
540 *(WORD *)(pFunc+1) = dgroup;
542 else
543 if ((pModule->flags & NE_FFLAGS_MULTIPLEDATA)
544 && (entry->flags & 1)) /* exported ? */
546 TRACE_(module)("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
547 *(WORD *)pFunc = 0x9090; /* nop, nop */
552 entry++;
554 } while ( (bundle->next)
555 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
559 /***********************************************************************
560 * PatchCodeHandle (KERNEL.110)
562 * Needed for self-loading modules.
564 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
566 WORD segnum;
567 WORD sel = SEL(hSeg);
568 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
569 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
571 TRACE_(module)("(%04x);\n", hSeg);
573 /* find the segment number of the module that belongs to hSeg */
574 for (segnum = 1; segnum <= pModule->seg_count; segnum++)
576 if (SEL(pSegTable[segnum-1].hSeg) == sel)
578 NE_FixupSegmentPrologs(pModule, segnum);
579 break;
583 return MAKELONG(hSeg, sel);
587 /***********************************************************************
588 * NE_GetDLLInitParams
590 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
591 WORD *hInst, WORD *ds, WORD *heap )
593 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
595 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
597 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
599 /* Not SINGLEDATA */
600 ERR_(dll)("Library is not marked SINGLEDATA\n");
601 exit(1);
603 else /* DATA NONE DLL */
605 *ds = 0;
606 *heap = 0;
609 else /* DATA SINGLE DLL */
611 if (pModule->dgroup) {
612 *ds = SEL(pSegTable[pModule->dgroup-1].hSeg);
613 *heap = pModule->heap_size;
615 else /* hmm, DLL has no dgroup,
616 but why has it NE_FFLAGS_SINGLEDATA set ?
617 Buggy DLL compiler ? */
619 *ds = 0;
620 *heap = 0;
624 *hInst = *ds ? GlobalHandle16(*ds) : pModule->self;
628 /***********************************************************************
629 * NE_InitDLL
631 * Call the DLL initialization code
633 static BOOL NE_InitDLL( NE_MODULE *pModule )
635 SEGTABLEENTRY *pSegTable;
636 WORD hInst, ds, heap;
637 CONTEXT86 context;
639 pSegTable = NE_SEG_TABLE( pModule );
641 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
642 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
644 /* Call USER signal handler for Win3.1 compatibility. */
645 TASK_CallTaskSignalProc( USIG16_DLL_LOAD, pModule->self );
647 if (!pModule->cs) return TRUE; /* no initialization code */
650 /* Registers at initialization must be:
651 * cx heap size
652 * di library instance
653 * ds data segment if any
654 * es:si command line (always 0)
657 memset( &context, 0, sizeof(context) );
659 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
661 context.Ecx = heap;
662 context.Edi = hInst;
663 context.SegDs = ds;
664 context.SegEs = ds; /* who knows ... */
666 context.SegCs = SEL(pSegTable[pModule->cs-1].hSeg);
667 context.Eip = pModule->ip;
668 context.Ebp = OFFSETOF(NtCurrentTeb()->cur_stack) + (WORD)&((STACK16FRAME*)0)->bp;
671 pModule->cs = 0; /* Don't initialize it twice */
672 TRACE_(dll)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
673 context.SegCs, context.Eip, context.SegDs,
674 LOWORD(context.Edi), LOWORD(context.Ecx) );
675 wine_call_to_16_regs_short( &context, 0 );
676 return TRUE;
679 /***********************************************************************
680 * NE_InitializeDLLs
682 * Recursively initialize all DLLs (according to the order in which
683 * they where loaded).
685 void NE_InitializeDLLs( HMODULE16 hModule )
687 NE_MODULE *pModule;
688 HMODULE16 *pDLL;
690 if (!(pModule = NE_GetPtr( hModule ))) return;
691 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
693 if (pModule->dlls_to_init)
695 HGLOBAL16 to_init = pModule->dlls_to_init;
696 pModule->dlls_to_init = 0;
697 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
699 NE_InitializeDLLs( *pDLL );
701 GlobalFree16( to_init );
703 NE_InitDLL( pModule );
707 /***********************************************************************
708 * NE_CallDllEntryPoint
710 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
712 typedef DWORD (WINAPI *WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
714 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
716 WORD hInst, ds, heap;
717 FARPROC16 entryPoint;
719 if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) return;
720 if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
721 if (!(entryPoint = GetProcAddress16( pModule->self, "DllEntryPoint" ))) return;
723 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
725 TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
726 NE_MODULE_NAME( pModule ),
727 SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
729 if ( pModule->flags & NE_FFLAGS_BUILTIN )
731 WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target;
733 entryProc( dwReason, hInst, ds, heap, 0, 0 );
735 else
737 LPBYTE stack = (LPBYTE)CURRENT_STACK16;
738 CONTEXT86 context;
740 memset( &context, 0, sizeof(context) );
741 context.SegDs = ds;
742 context.SegEs = ds; /* who knows ... */
744 context.SegCs = HIWORD(entryPoint);
745 context.Eip = LOWORD(entryPoint);
746 context.Ebp = OFFSETOF( NtCurrentTeb()->cur_stack )
747 + (WORD)&((STACK16FRAME*)0)->bp;
749 *(DWORD *)(stack - 4) = dwReason; /* dwReason */
750 *(WORD *) (stack - 6) = hInst; /* hInst */
751 *(WORD *) (stack - 8) = ds; /* wDS */
752 *(WORD *) (stack - 10) = heap; /* wHeapSize */
753 *(DWORD *)(stack - 14) = 0; /* dwReserved1 */
754 *(WORD *) (stack - 16) = 0; /* wReserved2 */
756 wine_call_to_16_regs_short( &context, 16 );
760 /***********************************************************************
761 * NE_DllProcessAttach
763 * Call the DllEntryPoint of all modules this one (recursively)
764 * depends on, according to the order in which they were loaded.
766 * Note that --as opposed to the PE module case-- there is no notion
767 * of 'module loaded into a process' for NE modules, and hence we
768 * have no place to store the fact that the DllEntryPoint of a
769 * given module was already called on behalf of this process (e.g.
770 * due to some earlier LoadLibrary16 call).
772 * Thus, we just call the DllEntryPoint twice in that case. Win9x
773 * appears to behave this way as well ...
775 * This routine must only be called with the Win16Lock held.
777 * FIXME: We should actually abort loading in case the DllEntryPoint
778 * returns FALSE ...
782 struct ne_init_list
784 int count;
785 int size;
786 NE_MODULE **module;
789 static void add_to_init_list( struct ne_init_list *list, NE_MODULE *hModule )
791 if ( list->count == list->size )
793 int newSize = list->size + 128;
794 NE_MODULE **newModule = HeapReAlloc( GetProcessHeap(), 0,
795 list->module, newSize*sizeof(NE_MODULE *) );
796 if ( !newModule )
798 FIXME_(dll)("Out of memory!");
799 return;
802 list->module = newModule;
803 list->size = newSize;
806 list->module[list->count++] = hModule;
809 static void free_init_list( struct ne_init_list *list )
811 if ( list->module )
813 HeapFree( GetProcessHeap(), 0, list->module );
814 memset( list, 0, sizeof(*list) );
818 static void fill_init_list( struct ne_init_list *list, HMODULE16 hModule )
820 NE_MODULE *pModule;
821 WORD *pModRef;
822 int i;
824 if (!(pModule = NE_GetPtr( hModule ))) return;
825 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
827 /* Never add a module twice */
828 for ( i = 0; i < list->count; i++ )
829 if ( list->module[i] == pModule )
830 return;
832 /* Check for recursive call */
833 if ( pModule->misc_flags & 0x80 ) return;
835 TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
837 /* Tag current module to prevent recursive loop */
838 pModule->misc_flags |= 0x80;
840 /* Recursively attach all DLLs this one depends on */
841 pModRef = NE_MODULE_TABLE( pModule );
842 for ( i = 0; i < pModule->modref_count; i++ )
843 if ( pModRef[i] )
844 fill_init_list( list, (HMODULE16)pModRef[i] );
846 /* Add current module */
847 add_to_init_list( list, pModule );
849 /* Remove recursion flag */
850 pModule->misc_flags &= ~0x80;
852 TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
855 static void call_init_list( struct ne_init_list *list )
857 int i;
858 for ( i = 0; i < list->count; i++ )
859 NE_CallDllEntryPoint( list->module[i], DLL_PROCESS_ATTACH );
862 void NE_DllProcessAttach( HMODULE16 hModule )
864 struct ne_init_list list;
865 memset( &list, 0, sizeof(list) );
867 fill_init_list( &list, hModule );
868 call_init_list( &list );
869 free_init_list( &list );
873 /***********************************************************************
874 * NE_Ne2MemFlags
876 * This function translates NE segment flags to GlobalAlloc flags
878 static WORD NE_Ne2MemFlags(WORD flags)
880 WORD memflags = 0;
881 #if 1
882 if (flags & NE_SEGFLAGS_DISCARDABLE)
883 memflags |= GMEM_DISCARDABLE;
884 if (flags & NE_SEGFLAGS_MOVEABLE ||
885 ( ! (flags & NE_SEGFLAGS_DATA) &&
886 ! (flags & NE_SEGFLAGS_LOADED) &&
887 ! (flags & NE_SEGFLAGS_ALLOCATED)
890 memflags |= GMEM_MOVEABLE;
891 memflags |= GMEM_ZEROINIT;
892 #else
893 memflags = GMEM_ZEROINIT | GMEM_FIXED;
894 #endif
895 return memflags;
898 /***********************************************************************
899 * MyAlloc (KERNEL.668) Wine-specific export
901 * MyAlloc() function for self-loading apps.
903 DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
905 WORD size = wSize << wElem;
906 HANDLE16 hMem = 0;
908 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
909 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
911 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
912 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
914 WORD hSel = SEL(hMem);
915 WORD access = SelectorAccessRights16(hSel,0,0);
917 access |= 2<<2; /* SEGMENT_CODE */
918 SelectorAccessRights16(hSel,1,access);
920 if (size)
921 return MAKELONG( hMem, SEL(hMem) );
922 else
923 return MAKELONG( 0, hMem );
926 /***********************************************************************
927 * NE_GetInstance
929 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
931 if ( !pModule->dgroup )
932 return pModule->self;
933 else
935 SEGTABLEENTRY *pSeg;
936 pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
937 return pSeg->hSeg;
941 /***********************************************************************
942 * NE_CreateSegment
944 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
946 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
947 int minsize;
948 unsigned char selflags;
950 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
952 if ( segnum < 1 || segnum > pModule->seg_count )
953 return FALSE;
955 if ( (pModule->flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
956 return TRUE; /* selfloader allocates segment itself */
958 if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->dgroup )
959 return TRUE; /* all but DGROUP only allocated once */
961 minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
962 if ( segnum == pModule->ss ) minsize += pModule->stack_size;
963 if ( segnum == pModule->dgroup ) minsize += pModule->heap_size;
965 selflags = (pSeg->flags & NE_SEGFLAGS_DATA) ? WINE_LDT_FLAGS_DATA : WINE_LDT_FLAGS_CODE;
966 if (pSeg->flags & NE_SEGFLAGS_32BIT) selflags |= WINE_LDT_FLAGS_32BIT;
967 pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags), minsize, pModule->self, selflags );
968 if (!pSeg->hSeg) return FALSE;
970 pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
971 return TRUE;
974 /***********************************************************************
975 * NE_CreateAllSegments
977 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
979 int i;
980 for ( i = 1; i <= pModule->seg_count; i++ )
981 if ( !NE_CreateSegment( pModule, i ) )
982 return FALSE;
984 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
985 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
986 return TRUE;
990 /**********************************************************************
991 * IsSharedSelector (KERNEL.345)
993 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
995 /* Check whether the selector belongs to a DLL */
996 NE_MODULE *pModule = NE_GetPtr( selector );
997 if (!pModule) return FALSE;
998 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;