Fixed a couple of bugs in _except_handler3.
[wine/wine-kai.git] / loader / ne / segment.c
blob0b5ad4ee68b5729d58b1501bfffe0dbdd34b8b3e
1 /*
2 * NE segment loading
4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
6 */
8 #include <assert.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/types.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <ctype.h>
15 #include <string.h>
17 #include "wine/winbase16.h"
18 #include "wine/library.h"
19 #include "global.h"
20 #include "task.h"
21 #include "file.h"
22 #include "module.h"
23 #include "stackframe.h"
24 #include "builtin16.h"
25 #include "debugtools.h"
27 DECLARE_DEBUG_CHANNEL(dll);
28 DECLARE_DEBUG_CHANNEL(fixup);
29 DECLARE_DEBUG_CHANNEL(module);
30 DECLARE_DEBUG_CHANNEL(segment);
33 * Relocation table entry
35 struct relocation_entry_s
37 BYTE address_type; /* Relocation address type */
38 BYTE relocation_type; /* Relocation type */
39 WORD offset; /* Offset in segment to fixup */
40 WORD target1; /* Target specification */
41 WORD target2; /* Target specification */
45 * Relocation address types
47 #define NE_RADDR_LOWBYTE 0
48 #define NE_RADDR_SELECTOR 2
49 #define NE_RADDR_POINTER32 3
50 #define NE_RADDR_OFFSET16 5
51 #define NE_RADDR_POINTER48 11
52 #define NE_RADDR_OFFSET32 13
55 * Relocation types
57 #define NE_RELTYPE_INTERNAL 0
58 #define NE_RELTYPE_ORDINAL 1
59 #define NE_RELTYPE_NAME 2
60 #define NE_RELTYPE_OSFIXUP 3
61 #define NE_RELFLAG_ADDITIVE 4
63 #define SEL(x) ((x)|1)
65 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);
67 /* ### start build ### */
68 extern WORD CALLBACK NE_CallTo16_word_ww(FARPROC16,WORD,WORD);
69 extern WORD CALLBACK NE_CallTo16_word_www(FARPROC16,WORD,WORD,WORD);
70 /* ### stop build ### */
72 /***********************************************************************
73 * NE_GetRelocAddrName
75 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
77 switch(addr_type & 0x7f)
79 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
80 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
81 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
82 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
83 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
84 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
86 return "???";
90 /***********************************************************************
91 * NE_LoadSegment
93 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
95 SEGTABLEENTRY *pSegTable, *pSeg;
96 WORD *pModuleTable;
97 WORD count, i, offset, next_offset;
98 HMODULE16 module;
99 FARPROC16 address = 0;
100 HFILE hf;
101 DWORD res;
102 struct relocation_entry_s *rep, *reloc_entries;
103 BYTE *func_name;
104 int size;
105 char* mem;
107 char buffer[256];
108 int ordinal, additive;
109 unsigned short *sp;
111 pSegTable = NE_SEG_TABLE( pModule );
112 pSeg = pSegTable + segnum - 1;
114 if (pSeg->flags & NE_SEGFLAGS_LOADED)
116 /* self-loader ? -> already loaded it */
117 if (pModule->flags & NE_FFLAGS_SELFLOAD)
118 return TRUE;
120 /* leave, except for DGROUP, as this may be the second instance */
121 if (segnum != pModule->dgroup)
122 return TRUE;
125 if (!pSeg->filepos) return TRUE; /* No file image, just return */
127 pModuleTable = NE_MODULE_TABLE( pModule );
129 hf = NE_OpenFile( pModule );
130 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
131 segnum, pSeg->hSeg, pSeg->flags );
132 SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
133 if (pSeg->size) size = pSeg->size;
134 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
135 mem = GlobalLock16(pSeg->hSeg);
136 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
138 /* Implement self-loading segments */
139 SELFLOADHEADER *selfloadheader;
140 DWORD oldstack;
141 HFILE hFile32;
142 HFILE16 hFile16;
144 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
145 oldstack = NtCurrentTeb()->cur_stack;
146 NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
147 0xff00 - sizeof(STACK16FRAME));
149 TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
150 pModule->self,hf,segnum );
151 DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
152 0, FALSE, DUPLICATE_SAME_ACCESS );
153 hFile16 = Win32HandleToDosFileHandle( hFile32 );
154 pSeg->hSeg = NE_CallTo16_word_www( selfloadheader->LoadAppSeg,
155 pModule->self, hFile16, segnum );
156 TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
157 _lclose16( hFile16 );
158 NtCurrentTeb()->cur_stack = oldstack;
160 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
161 ReadFile(hf, mem, size, &res, NULL);
162 else {
164 The following bit of code for "iterated segments" was written without
165 any documentation on the format of these segments. It seems to work,
166 but may be missing something. If you have any doc please either send
167 it to me or fix the code yourself. gfm@werple.mira.net.au
169 char* buff = HeapAlloc(GetProcessHeap(), 0, size);
170 char* curr = buff;
172 if(buff == NULL) {
173 WARN_(dll)("Memory exausted!");
174 return FALSE;
177 ReadFile(hf, buff, size, &res, NULL);
178 while(curr < buff + size) {
179 unsigned int rept = *((short*) curr)++;
180 unsigned int len = *((short*) curr)++;
181 for(; rept > 0; rept--) {
182 char* bytes = curr;
183 unsigned int byte;
184 for(byte = 0; byte < len; byte++)
185 *mem++ = *bytes++;
187 curr += len;
189 HeapFree(GetProcessHeap(), 0, buff);
192 pSeg->flags |= NE_SEGFLAGS_LOADED;
194 /* Perform exported function prolog fixups */
195 NE_FixupSegmentPrologs( pModule, segnum );
197 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
198 return TRUE; /* No relocation data, we are done */
200 ReadFile(hf, &count, sizeof(count), &res, NULL);
201 if (!count) return TRUE;
203 TRACE_(fixup)("Fixups for %.*s, segment %d, hSeg %04x\n",
204 *((BYTE *)pModule + pModule->name_table),
205 (char *)pModule + pModule->name_table + 1,
206 segnum, pSeg->hSeg );
207 TRACE_(segment)("Fixups for %.*s, segment %d, hSeg %04x\n",
208 *((BYTE *)pModule + pModule->name_table),
209 (char *)pModule + pModule->name_table + 1,
210 segnum, pSeg->hSeg );
212 reloc_entries = (struct relocation_entry_s *)HeapAlloc(GetProcessHeap(), 0, count * sizeof(struct relocation_entry_s));
213 if(reloc_entries == NULL) {
214 WARN_(fixup)("Not enough memory for relocation entries!");
215 return FALSE;
217 if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
218 (res != count * sizeof(struct relocation_entry_s)))
220 WARN_(fixup)("Unable to read relocation information\n" );
221 return FALSE;
225 * Go through the relocation table one entry at a time.
227 rep = reloc_entries;
228 for (i = 0; i < count; i++, rep++)
231 * Get the target address corresponding to this entry.
234 /* If additive, there is no target chain list. Instead, add source
235 and target */
236 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
237 rep->relocation_type &= 0x3;
239 switch (rep->relocation_type)
241 case NE_RELTYPE_ORDINAL:
242 module = pModuleTable[rep->target1-1];
243 ordinal = rep->target2;
244 address = NE_GetEntryPoint( module, ordinal );
245 if (!address)
247 NE_MODULE *pTarget = NE_GetPtr( module );
248 if (!pTarget)
249 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
250 module, rep->target1,
251 *((BYTE *)pModule + pModule->name_table),
252 *((BYTE *)pModule + pModule->name_table),
253 (char *)pModule + pModule->name_table + 1 );
254 else
256 ERR_(fixup)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
257 *((BYTE *)pTarget + pTarget->name_table),
258 (char *)pTarget + pTarget->name_table + 1,
259 ordinal );
260 address = (FARPROC16)0xdeadbeef;
263 if (TRACE_ON(fixup))
265 NE_MODULE *pTarget = NE_GetPtr( module );
266 TRACE_(fixup)("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
267 *((BYTE *)pTarget + pTarget->name_table),
268 (char *)pTarget + pTarget->name_table + 1,
269 ordinal, HIWORD(address), LOWORD(address),
270 NE_GetRelocAddrName( rep->address_type, additive ) );
272 break;
274 case NE_RELTYPE_NAME:
275 module = pModuleTable[rep->target1-1];
276 func_name = (char *)pModule + pModule->import_table + rep->target2;
277 memcpy( buffer, func_name+1, *func_name );
278 buffer[*func_name] = '\0';
279 func_name = buffer;
280 ordinal = NE_GetOrdinal( module, func_name );
281 address = NE_GetEntryPoint( module, ordinal );
283 if (ERR_ON(fixup) && !address)
285 NE_MODULE *pTarget = NE_GetPtr( module );
286 ERR_(fixup)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
287 *((BYTE *)pTarget + pTarget->name_table),
288 (char *)pTarget + pTarget->name_table + 1, func_name );
290 if (!address) address = (FARPROC16) 0xdeadbeef;
291 if (TRACE_ON(fixup))
293 NE_MODULE *pTarget = NE_GetPtr( module );
294 TRACE_(fixup)("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
295 *((BYTE *)pTarget + pTarget->name_table),
296 (char *)pTarget + pTarget->name_table + 1,
297 func_name, HIWORD(address), LOWORD(address),
298 NE_GetRelocAddrName( rep->address_type, additive ) );
300 break;
302 case NE_RELTYPE_INTERNAL:
303 if ((rep->target1 & 0xff) == 0xff)
305 address = NE_GetEntryPoint( pModule->self, rep->target2 );
307 else
309 address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
312 TRACE_(fixup)("%d: %04x:%04x %s\n",
313 i + 1, HIWORD(address), LOWORD(address),
314 NE_GetRelocAddrName( rep->address_type, additive ) );
315 break;
317 case NE_RELTYPE_OSFIXUP:
318 /* Relocation type 7:
320 * These appear to be used as fixups for the Windows
321 * floating point emulator. Let's just ignore them and
322 * try to use the hardware floating point. Linux should
323 * successfully emulate the coprocessor if it doesn't
324 * exist.
326 TRACE_(fixup)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
327 i + 1, rep->relocation_type, rep->offset,
328 rep->target1, rep->target2,
329 NE_GetRelocAddrName( rep->address_type, additive ) );
330 continue;
333 offset = rep->offset;
335 /* Apparently, high bit of address_type is sometimes set; */
336 /* we ignore it for now */
337 if (rep->address_type > NE_RADDR_OFFSET32)
339 char module[10];
340 GetModuleName16( pModule->self, module, sizeof(module) );
341 ERR_(fixup)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
342 module, rep->address_type );
345 if (additive)
347 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
348 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
349 switch (rep->address_type & 0x7f)
351 case NE_RADDR_LOWBYTE:
352 *(BYTE *)sp += LOBYTE((int)address);
353 break;
354 case NE_RADDR_OFFSET16:
355 *sp += LOWORD(address);
356 break;
357 case NE_RADDR_POINTER32:
358 *sp += LOWORD(address);
359 *(sp+1) = HIWORD(address);
360 break;
361 case NE_RADDR_SELECTOR:
362 /* Borland creates additive records with offset zero. Strange, but OK */
363 if (*sp)
364 ERR_(fixup)("Additive selector to %04x.Please report\n",*sp);
365 else
366 *sp = HIWORD(address);
367 break;
368 default:
369 goto unknown;
372 else /* non-additive fixup */
376 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
377 next_offset = *sp;
378 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
379 switch (rep->address_type & 0x7f)
381 case NE_RADDR_LOWBYTE:
382 *(BYTE *)sp = LOBYTE((int)address);
383 break;
384 case NE_RADDR_OFFSET16:
385 *sp = LOWORD(address);
386 break;
387 case NE_RADDR_POINTER32:
388 *(FARPROC16 *)sp = address;
389 break;
390 case NE_RADDR_SELECTOR:
391 *sp = SELECTOROF(address);
392 break;
393 default:
394 goto unknown;
396 if (next_offset == offset) break; /* avoid infinite loop */
397 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
398 offset = next_offset;
399 } while (offset != 0xffff);
403 HeapFree(GetProcessHeap(), 0, reloc_entries);
404 return TRUE;
406 unknown:
407 WARN_(fixup)("WARNING: %d: unknown ADDR TYPE %d, "
408 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
409 i + 1, rep->address_type, rep->relocation_type,
410 rep->offset, rep->target1, rep->target2);
411 HeapFree(GetProcessHeap(), 0, reloc_entries);
412 return FALSE;
416 /***********************************************************************
417 * NE_LoadAllSegments
419 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
421 int i;
422 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
424 if (pModule->flags & NE_FFLAGS_SELFLOAD)
426 HFILE hf;
427 HFILE16 hFile16;
428 HGLOBAL16 sel;
429 /* Handle self-loading modules */
430 SELFLOADHEADER *selfloadheader;
431 HMODULE16 mod = GetModuleHandle16("KERNEL");
432 DWORD oldstack;
434 TRACE_(module)("%.*s is a self-loading module!\n",
435 *((BYTE*)pModule + pModule->name_table),
436 (char *)pModule + pModule->name_table + 1);
437 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
438 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) );
439 selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc");
440 selfloadheader->MyAlloc = GetProcAddress16(mod,"MyAlloc");
441 selfloadheader->SetOwner = GetProcAddress16(mod,"FarSetOwner");
442 sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 );
443 pModule->self_loading_sel = SEL(sel);
444 FarSetOwner16( sel, pModule->self );
445 oldstack = NtCurrentTeb()->cur_stack;
446 NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
447 0xff00 - sizeof(STACK16FRAME) );
449 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule),
450 GetCurrentProcess(), &hf, 0, FALSE, DUPLICATE_SAME_ACCESS );
451 hFile16 = Win32HandleToDosFileHandle( hf );
452 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
453 pModule->self,hFile16);
454 NE_CallTo16_word_ww(selfloadheader->BootApp, pModule->self,hFile16);
455 TRACE_(dll)("Return from CallBootAppProc\n");
456 _lclose16(hFile16);
457 NtCurrentTeb()->cur_stack = oldstack;
459 for (i = 2; i <= pModule->seg_count; i++)
460 if (!NE_LoadSegment( pModule, i )) return FALSE;
462 else
464 for (i = 1; i <= pModule->seg_count; i++)
465 if (!NE_LoadSegment( pModule, i )) return FALSE;
467 return TRUE;
471 /***********************************************************************
472 * NE_FixupSegmentPrologs
474 * Fixup exported functions prologs of one segment
476 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
478 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
479 ET_BUNDLE *bundle;
480 ET_ENTRY *entry;
481 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
482 BYTE *pSeg, *pFunc;
484 TRACE_(module)("(%d);\n", segnum);
486 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
488 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
489 return;
492 if (!pModule->dgroup) return;
494 if (!(dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg))) return;
496 pSeg = MapSL( MAKESEGPTR(sel, 0) );
498 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);
500 do {
501 TRACE_(module)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
502 if (!(num_entries = bundle->last - bundle->first))
503 return;
504 entry = (ET_ENTRY *)((BYTE *)bundle+6);
505 while (num_entries--)
507 /*TRACE_(module)("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
508 if (entry->segnum == segnum)
510 pFunc = ((BYTE *)pSeg+entry->offs);
511 TRACE_(module)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
512 if (*(pFunc+2) == 0x90)
514 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
516 TRACE_(module)("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
517 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
520 if (*(WORD *)pFunc == 0xd88c)
522 if ((entry->flags & 2)) /* public data ? */
524 TRACE_(module)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
525 *pFunc = 0xb8; /* mov ax, */
526 *(WORD *)(pFunc+1) = dgroup;
528 else
529 if ((pModule->flags & NE_FFLAGS_MULTIPLEDATA)
530 && (entry->flags & 1)) /* exported ? */
532 TRACE_(module)("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
533 *(WORD *)pFunc = 0x9090; /* nop, nop */
538 entry++;
540 } while ( (bundle->next)
541 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
545 /***********************************************************************
546 * PatchCodeHandle (KERNEL.110)
548 * Needed for self-loading modules.
550 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
552 WORD segnum;
553 WORD sel = SEL(hSeg);
554 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
555 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
557 TRACE_(module)("(%04x);\n", hSeg);
559 /* find the segment number of the module that belongs to hSeg */
560 for (segnum = 1; segnum <= pModule->seg_count; segnum++)
562 if (SEL(pSegTable[segnum-1].hSeg) == sel)
564 NE_FixupSegmentPrologs(pModule, segnum);
565 break;
569 return MAKELONG(hSeg, sel);
573 /***********************************************************************
574 * NE_GetDLLInitParams
576 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
577 WORD *hInst, WORD *ds, WORD *heap )
579 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
581 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
583 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
585 /* Not SINGLEDATA */
586 ERR_(dll)("Library is not marked SINGLEDATA\n");
587 exit(1);
589 else /* DATA NONE DLL */
591 *ds = 0;
592 *heap = 0;
595 else /* DATA SINGLE DLL */
597 if (pModule->dgroup) {
598 *ds = SEL(pSegTable[pModule->dgroup-1].hSeg);
599 *heap = pModule->heap_size;
601 else /* hmm, DLL has no dgroup,
602 but why has it NE_FFLAGS_SINGLEDATA set ?
603 Buggy DLL compiler ? */
605 *ds = 0;
606 *heap = 0;
610 *hInst = *ds ? GlobalHandle16(*ds) : pModule->self;
614 /***********************************************************************
615 * NE_InitDLL
617 * Call the DLL initialization code
619 static BOOL NE_InitDLL( NE_MODULE *pModule )
621 SEGTABLEENTRY *pSegTable;
622 WORD hInst, ds, heap;
623 CONTEXT86 context;
625 pSegTable = NE_SEG_TABLE( pModule );
627 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
628 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
630 /* Call USER signal handler for Win3.1 compatibility. */
631 TASK_CallTaskSignalProc( USIG16_DLL_LOAD, pModule->self );
633 if (!pModule->cs) return TRUE; /* no initialization code */
636 /* Registers at initialization must be:
637 * cx heap size
638 * di library instance
639 * ds data segment if any
640 * es:si command line (always 0)
643 memset( &context, 0, sizeof(context) );
645 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
647 context.Ecx = heap;
648 context.Edi = hInst;
649 context.SegDs = ds;
650 context.SegEs = ds; /* who knows ... */
652 context.SegCs = SEL(pSegTable[pModule->cs-1].hSeg);
653 context.Eip = pModule->ip;
654 context.Ebp = OFFSETOF(NtCurrentTeb()->cur_stack) + (WORD)&((STACK16FRAME*)0)->bp;
657 pModule->cs = 0; /* Don't initialize it twice */
658 TRACE_(dll)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
659 context.SegCs, context.Eip, context.SegDs,
660 LOWORD(context.Edi), LOWORD(context.Ecx) );
661 wine_call_to_16_regs_short( &context, 0 );
662 return TRUE;
665 /***********************************************************************
666 * NE_InitializeDLLs
668 * Recursively initialize all DLLs (according to the order in which
669 * they where loaded).
671 void NE_InitializeDLLs( HMODULE16 hModule )
673 NE_MODULE *pModule;
674 HMODULE16 *pDLL;
676 if (!(pModule = NE_GetPtr( hModule ))) return;
677 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
679 if (pModule->dlls_to_init)
681 HGLOBAL16 to_init = pModule->dlls_to_init;
682 pModule->dlls_to_init = 0;
683 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
685 NE_InitializeDLLs( *pDLL );
687 GlobalFree16( to_init );
689 NE_InitDLL( pModule );
693 /***********************************************************************
694 * NE_CallDllEntryPoint
696 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
698 typedef DWORD WINAPI (*WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
700 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
702 WORD hInst, ds, heap;
703 FARPROC16 entryPoint;
705 if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) return;
706 if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
707 if (!(entryPoint = GetProcAddress16( pModule->self, "DllEntryPoint" ))) return;
709 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
711 TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
712 NE_MODULE_NAME( pModule ),
713 SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
715 if ( pModule->flags & NE_FFLAGS_BUILTIN )
717 WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target;
719 entryProc( dwReason, hInst, ds, heap, 0, 0 );
721 else
723 LPBYTE stack = (LPBYTE)CURRENT_STACK16;
724 CONTEXT86 context;
726 memset( &context, 0, sizeof(context) );
727 context.SegDs = ds;
728 context.SegEs = ds; /* who knows ... */
730 context.SegCs = HIWORD(entryPoint);
731 context.Eip = LOWORD(entryPoint);
732 context.Ebp = OFFSETOF( NtCurrentTeb()->cur_stack )
733 + (WORD)&((STACK16FRAME*)0)->bp;
735 *(DWORD *)(stack - 4) = dwReason; /* dwReason */
736 *(WORD *) (stack - 6) = hInst; /* hInst */
737 *(WORD *) (stack - 8) = ds; /* wDS */
738 *(WORD *) (stack - 10) = heap; /* wHeapSize */
739 *(DWORD *)(stack - 14) = 0; /* dwReserved1 */
740 *(WORD *) (stack - 16) = 0; /* wReserved2 */
742 wine_call_to_16_regs_short( &context, 16 );
746 /***********************************************************************
747 * NE_DllProcessAttach
749 * Call the DllEntryPoint of all modules this one (recursively)
750 * depends on, according to the order in which they were loaded.
752 * Note that --as opposed to the PE module case-- there is no notion
753 * of 'module loaded into a process' for NE modules, and hence we
754 * have no place to store the fact that the DllEntryPoint of a
755 * given module was already called on behalf of this process (e.g.
756 * due to some earlier LoadLibrary16 call).
758 * Thus, we just call the DllEntryPoint twice in that case. Win9x
759 * appears to behave this way as well ...
761 * This routine must only be called with the Win16Lock held.
763 * FIXME: We should actually abort loading in case the DllEntryPoint
764 * returns FALSE ...
768 struct ne_init_list
770 int count;
771 int size;
772 NE_MODULE **module;
775 static void add_to_init_list( struct ne_init_list *list, NE_MODULE *hModule )
777 if ( list->count == list->size )
779 int newSize = list->size + 128;
780 NE_MODULE **newModule = HeapReAlloc( GetProcessHeap(), 0,
781 list->module, newSize*sizeof(NE_MODULE *) );
782 if ( !newModule )
784 FIXME_(dll)("Out of memory!");
785 return;
788 list->module = newModule;
789 list->size = newSize;
792 list->module[list->count++] = hModule;
795 static void free_init_list( struct ne_init_list *list )
797 if ( list->module )
799 HeapFree( GetProcessHeap(), 0, list->module );
800 memset( list, 0, sizeof(*list) );
804 static void fill_init_list( struct ne_init_list *list, HMODULE16 hModule )
806 NE_MODULE *pModule;
807 WORD *pModRef;
808 int i;
810 if (!(pModule = NE_GetPtr( hModule ))) return;
811 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
813 /* Never add a module twice */
814 for ( i = 0; i < list->count; i++ )
815 if ( list->module[i] == pModule )
816 return;
818 /* Check for recursive call */
819 if ( pModule->misc_flags & 0x80 ) return;
821 TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
823 /* Tag current module to prevent recursive loop */
824 pModule->misc_flags |= 0x80;
826 /* Recursively attach all DLLs this one depends on */
827 pModRef = NE_MODULE_TABLE( pModule );
828 for ( i = 0; i < pModule->modref_count; i++ )
829 if ( pModRef[i] )
830 fill_init_list( list, (HMODULE16)pModRef[i] );
832 /* Add current module */
833 add_to_init_list( list, pModule );
835 /* Remove recursion flag */
836 pModule->misc_flags &= ~0x80;
838 TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
841 static void call_init_list( struct ne_init_list *list )
843 int i;
844 for ( i = 0; i < list->count; i++ )
845 NE_CallDllEntryPoint( list->module[i], DLL_PROCESS_ATTACH );
848 void NE_DllProcessAttach( HMODULE16 hModule )
850 struct ne_init_list list;
851 memset( &list, 0, sizeof(list) );
853 fill_init_list( &list, hModule );
854 call_init_list( &list );
855 free_init_list( &list );
859 /***********************************************************************
860 * NE_Ne2MemFlags
862 * This function translates NE segment flags to GlobalAlloc flags
864 static WORD NE_Ne2MemFlags(WORD flags)
866 WORD memflags = 0;
867 #if 1
868 if (flags & NE_SEGFLAGS_DISCARDABLE)
869 memflags |= GMEM_DISCARDABLE;
870 if (flags & NE_SEGFLAGS_MOVEABLE ||
871 ( ! (flags & NE_SEGFLAGS_DATA) &&
872 ! (flags & NE_SEGFLAGS_LOADED) &&
873 ! (flags & NE_SEGFLAGS_ALLOCATED)
876 memflags |= GMEM_MOVEABLE;
877 memflags |= GMEM_ZEROINIT;
878 #else
879 memflags = GMEM_ZEROINIT | GMEM_FIXED;
880 #endif
881 return memflags;
884 /***********************************************************************
885 * MyAlloc (KERNEL.668) Wine-specific export
887 * MyAlloc() function for self-loading apps.
889 DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
891 WORD size = wSize << wElem;
892 HANDLE16 hMem = 0;
894 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
895 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
897 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
898 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
900 WORD hSel = SEL(hMem);
901 WORD access = SelectorAccessRights16(hSel,0,0);
903 access |= 2<<2; /* SEGMENT_CODE */
904 SelectorAccessRights16(hSel,1,access);
906 if (size)
907 return MAKELONG( hMem, SEL(hMem) );
908 else
909 return MAKELONG( 0, hMem );
912 /***********************************************************************
913 * NE_GetInstance
915 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
917 if ( !pModule->dgroup )
918 return pModule->self;
919 else
921 SEGTABLEENTRY *pSeg;
922 pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
923 return pSeg->hSeg;
927 /***********************************************************************
928 * NE_CreateSegment
930 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
932 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
933 int minsize;
934 unsigned char selflags;
936 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
938 if ( segnum < 1 || segnum > pModule->seg_count )
939 return FALSE;
941 if ( (pModule->flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
942 return TRUE; /* selfloader allocates segment itself */
944 if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->dgroup )
945 return TRUE; /* all but DGROUP only allocated once */
947 minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
948 if ( segnum == pModule->ss ) minsize += pModule->stack_size;
949 if ( segnum == pModule->dgroup ) minsize += pModule->heap_size;
951 selflags = (pSeg->flags & NE_SEGFLAGS_DATA) ? WINE_LDT_FLAGS_DATA : WINE_LDT_FLAGS_CODE;
952 if (pSeg->flags & NE_SEGFLAGS_32BIT) selflags |= WINE_LDT_FLAGS_32BIT;
953 pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags), minsize, pModule->self, selflags );
954 if (!pSeg->hSeg) return FALSE;
956 pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
957 return TRUE;
960 /***********************************************************************
961 * NE_CreateAllSegments
963 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
965 int i;
966 for ( i = 1; i <= pModule->seg_count; i++ )
967 if ( !NE_CreateSegment( pModule, i ) )
968 return FALSE;
970 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
971 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
972 return TRUE;
976 /**********************************************************************
977 * IsSharedSelector (KERNEL.345)
979 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
981 /* Check whether the selector belongs to a DLL */
982 NE_MODULE *pModule = NE_GetPtr( selector );
983 if (!pModule) return FALSE;
984 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;