Release 20010216.
[wine/multimedia.git] / loader / ne / segment.c
blobde61c3c75ed9a5546589ff1bdaa8f0c79f54c2e4
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 <sys/stat.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 #include <ctype.h>
16 #include <string.h>
18 #include "wine/winbase16.h"
19 #include "wine/library.h"
20 #include "global.h"
21 #include "task.h"
22 #include "file.h"
23 #include "module.h"
24 #include "stackframe.h"
25 #include "builtin16.h"
26 #include "debugtools.h"
28 DECLARE_DEBUG_CHANNEL(dll);
29 DECLARE_DEBUG_CHANNEL(fixup);
30 DECLARE_DEBUG_CHANNEL(module);
31 DECLARE_DEBUG_CHANNEL(segment);
34 * Relocation table entry
36 struct relocation_entry_s
38 BYTE address_type; /* Relocation address type */
39 BYTE relocation_type; /* Relocation type */
40 WORD offset; /* Offset in segment to fixup */
41 WORD target1; /* Target specification */
42 WORD target2; /* Target specification */
46 * Relocation address types
48 #define NE_RADDR_LOWBYTE 0
49 #define NE_RADDR_SELECTOR 2
50 #define NE_RADDR_POINTER32 3
51 #define NE_RADDR_OFFSET16 5
52 #define NE_RADDR_POINTER48 11
53 #define NE_RADDR_OFFSET32 13
56 * Relocation types
58 #define NE_RELTYPE_INTERNAL 0
59 #define NE_RELTYPE_ORDINAL 1
60 #define NE_RELTYPE_NAME 2
61 #define NE_RELTYPE_OSFIXUP 3
62 #define NE_RELFLAG_ADDITIVE 4
64 #define SEL(x) ((x)|1)
66 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);
68 /* ### start build ### */
69 extern WORD CALLBACK NE_CallTo16_word_ww(FARPROC16,WORD,WORD);
70 extern WORD CALLBACK NE_CallTo16_word_www(FARPROC16,WORD,WORD,WORD);
71 /* ### stop build ### */
73 /***********************************************************************
74 * NE_GetRelocAddrName
76 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
78 switch(addr_type & 0x7f)
80 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
81 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
82 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
83 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
84 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
85 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
87 return "???";
91 /***********************************************************************
92 * NE_LoadSegment
94 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
96 SEGTABLEENTRY *pSegTable, *pSeg;
97 WORD *pModuleTable;
98 WORD count, i, offset, next_offset;
99 HMODULE16 module;
100 FARPROC16 address = 0;
101 HFILE hf;
102 DWORD res;
103 struct relocation_entry_s *rep, *reloc_entries;
104 BYTE *func_name;
105 int size;
106 char* mem;
108 char buffer[256];
109 int ordinal, additive;
110 unsigned short *sp;
112 pSegTable = NE_SEG_TABLE( pModule );
113 pSeg = pSegTable + segnum - 1;
115 if (pSeg->flags & NE_SEGFLAGS_LOADED)
117 /* self-loader ? -> already loaded it */
118 if (pModule->flags & NE_FFLAGS_SELFLOAD)
119 return TRUE;
121 /* leave, except for DGROUP, as this may be the second instance */
122 if (segnum != pModule->dgroup)
123 return TRUE;
126 if (!pSeg->filepos) return TRUE; /* No file image, just return */
128 pModuleTable = NE_MODULE_TABLE( pModule );
130 hf = NE_OpenFile( pModule );
131 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
132 segnum, pSeg->hSeg, pSeg->flags );
133 SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
134 if (pSeg->size) size = pSeg->size;
135 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
136 mem = GlobalLock16(pSeg->hSeg);
137 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
139 /* Implement self-loading segments */
140 SELFLOADHEADER *selfloadheader;
141 DWORD oldstack;
142 HFILE hFile32;
143 HFILE16 hFile16;
145 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
146 oldstack = NtCurrentTeb()->cur_stack;
147 NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
148 0xff00 - sizeof(STACK16FRAME));
150 TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
151 pModule->self,hf,segnum );
152 DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
153 0, FALSE, DUPLICATE_SAME_ACCESS );
154 hFile16 = Win32HandleToDosFileHandle( hFile32 );
155 pSeg->hSeg = NE_CallTo16_word_www( selfloadheader->LoadAppSeg,
156 pModule->self, hFile16, segnum );
157 TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
158 _lclose16( hFile16 );
159 NtCurrentTeb()->cur_stack = oldstack;
161 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
162 ReadFile(hf, mem, size, &res, NULL);
163 else {
165 The following bit of code for "iterated segments" was written without
166 any documentation on the format of these segments. It seems to work,
167 but may be missing something. If you have any doc please either send
168 it to me or fix the code yourself. gfm@werple.mira.net.au
170 char* buff = HeapAlloc(GetProcessHeap(), 0, size);
171 char* curr = buff;
173 if(buff == NULL) {
174 WARN_(dll)("Memory exausted!");
175 return FALSE;
178 ReadFile(hf, buff, size, &res, NULL);
179 while(curr < buff + size) {
180 unsigned int rept = *((short*) curr)++;
181 unsigned int len = *((short*) curr)++;
182 for(; rept > 0; rept--) {
183 char* bytes = curr;
184 unsigned int byte;
185 for(byte = 0; byte < len; byte++)
186 *mem++ = *bytes++;
188 curr += len;
190 HeapFree(GetProcessHeap(), 0, buff);
193 pSeg->flags |= NE_SEGFLAGS_LOADED;
195 /* Perform exported function prolog fixups */
196 NE_FixupSegmentPrologs( pModule, segnum );
198 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
199 return TRUE; /* No relocation data, we are done */
201 ReadFile(hf, &count, sizeof(count), &res, NULL);
202 if (!count) return TRUE;
204 TRACE_(fixup)("Fixups for %.*s, segment %d, hSeg %04x\n",
205 *((BYTE *)pModule + pModule->name_table),
206 (char *)pModule + pModule->name_table + 1,
207 segnum, pSeg->hSeg );
208 TRACE_(segment)("Fixups for %.*s, segment %d, hSeg %04x\n",
209 *((BYTE *)pModule + pModule->name_table),
210 (char *)pModule + pModule->name_table + 1,
211 segnum, pSeg->hSeg );
213 reloc_entries = (struct relocation_entry_s *)HeapAlloc(GetProcessHeap(), 0, count * sizeof(struct relocation_entry_s));
214 if(reloc_entries == NULL) {
215 WARN_(fixup)("Not enough memory for relocation entries!");
216 return FALSE;
218 if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
219 (res != count * sizeof(struct relocation_entry_s)))
221 WARN_(fixup)("Unable to read relocation information\n" );
222 return FALSE;
226 * Go through the relocation table one entry at a time.
228 rep = reloc_entries;
229 for (i = 0; i < count; i++, rep++)
232 * Get the target address corresponding to this entry.
235 /* If additive, there is no target chain list. Instead, add source
236 and target */
237 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
238 rep->relocation_type &= 0x3;
240 switch (rep->relocation_type)
242 case NE_RELTYPE_ORDINAL:
243 module = pModuleTable[rep->target1-1];
244 ordinal = rep->target2;
245 address = NE_GetEntryPoint( module, ordinal );
246 if (!address)
248 NE_MODULE *pTarget = NE_GetPtr( module );
249 if (!pTarget)
250 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
251 module, rep->target1,
252 *((BYTE *)pModule + pModule->name_table),
253 *((BYTE *)pModule + pModule->name_table),
254 (char *)pModule + pModule->name_table + 1 );
255 else
257 ERR_(fixup)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
258 *((BYTE *)pTarget + pTarget->name_table),
259 (char *)pTarget + pTarget->name_table + 1,
260 ordinal );
261 address = (FARPROC16)0xdeadbeef;
264 if (TRACE_ON(fixup))
266 NE_MODULE *pTarget = NE_GetPtr( module );
267 TRACE_(fixup)("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
268 *((BYTE *)pTarget + pTarget->name_table),
269 (char *)pTarget + pTarget->name_table + 1,
270 ordinal, HIWORD(address), LOWORD(address),
271 NE_GetRelocAddrName( rep->address_type, additive ) );
273 break;
275 case NE_RELTYPE_NAME:
276 module = pModuleTable[rep->target1-1];
277 func_name = (char *)pModule + pModule->import_table + rep->target2;
278 memcpy( buffer, func_name+1, *func_name );
279 buffer[*func_name] = '\0';
280 func_name = buffer;
281 ordinal = NE_GetOrdinal( module, func_name );
282 address = NE_GetEntryPoint( module, ordinal );
284 if (ERR_ON(fixup) && !address)
286 NE_MODULE *pTarget = NE_GetPtr( module );
287 ERR_(fixup)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
288 *((BYTE *)pTarget + pTarget->name_table),
289 (char *)pTarget + pTarget->name_table + 1, func_name );
291 if (!address) address = (FARPROC16) 0xdeadbeef;
292 if (TRACE_ON(fixup))
294 NE_MODULE *pTarget = NE_GetPtr( module );
295 TRACE_(fixup)("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
296 *((BYTE *)pTarget + pTarget->name_table),
297 (char *)pTarget + pTarget->name_table + 1,
298 func_name, HIWORD(address), LOWORD(address),
299 NE_GetRelocAddrName( rep->address_type, additive ) );
301 break;
303 case NE_RELTYPE_INTERNAL:
304 if ((rep->target1 & 0xff) == 0xff)
306 address = NE_GetEntryPoint( pModule->self, rep->target2 );
308 else
310 address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
313 TRACE_(fixup)("%d: %04x:%04x %s\n",
314 i + 1, HIWORD(address), LOWORD(address),
315 NE_GetRelocAddrName( rep->address_type, additive ) );
316 break;
318 case NE_RELTYPE_OSFIXUP:
319 /* Relocation type 7:
321 * These appear to be used as fixups for the Windows
322 * floating point emulator. Let's just ignore them and
323 * try to use the hardware floating point. Linux should
324 * successfully emulate the coprocessor if it doesn't
325 * exist.
327 TRACE_(fixup)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
328 i + 1, rep->relocation_type, rep->offset,
329 rep->target1, rep->target2,
330 NE_GetRelocAddrName( rep->address_type, additive ) );
331 continue;
334 offset = rep->offset;
336 /* Apparently, high bit of address_type is sometimes set; */
337 /* we ignore it for now */
338 if (rep->address_type > NE_RADDR_OFFSET32)
340 char module[10];
341 GetModuleName16( pModule->self, module, sizeof(module) );
342 ERR_(fixup)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
343 module, rep->address_type );
346 if (additive)
348 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
349 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
350 switch (rep->address_type & 0x7f)
352 case NE_RADDR_LOWBYTE:
353 *(BYTE *)sp += LOBYTE((int)address);
354 break;
355 case NE_RADDR_OFFSET16:
356 *sp += LOWORD(address);
357 break;
358 case NE_RADDR_POINTER32:
359 *sp += LOWORD(address);
360 *(sp+1) = HIWORD(address);
361 break;
362 case NE_RADDR_SELECTOR:
363 /* Borland creates additive records with offset zero. Strange, but OK */
364 if (*sp)
365 ERR_(fixup)("Additive selector to %04x.Please report\n",*sp);
366 else
367 *sp = HIWORD(address);
368 break;
369 default:
370 goto unknown;
373 else /* non-additive fixup */
377 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
378 next_offset = *sp;
379 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
380 switch (rep->address_type & 0x7f)
382 case NE_RADDR_LOWBYTE:
383 *(BYTE *)sp = LOBYTE((int)address);
384 break;
385 case NE_RADDR_OFFSET16:
386 *sp = LOWORD(address);
387 break;
388 case NE_RADDR_POINTER32:
389 *(FARPROC16 *)sp = address;
390 break;
391 case NE_RADDR_SELECTOR:
392 *sp = SELECTOROF(address);
393 break;
394 default:
395 goto unknown;
397 if (next_offset == offset) break; /* avoid infinite loop */
398 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
399 offset = next_offset;
400 } while (offset != 0xffff);
404 HeapFree(GetProcessHeap(), 0, reloc_entries);
405 return TRUE;
407 unknown:
408 WARN_(fixup)("WARNING: %d: unknown ADDR TYPE %d, "
409 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
410 i + 1, rep->address_type, rep->relocation_type,
411 rep->offset, rep->target1, rep->target2);
412 HeapFree(GetProcessHeap(), 0, reloc_entries);
413 return FALSE;
417 /***********************************************************************
418 * NE_LoadAllSegments
420 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
422 int i;
423 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
425 if (pModule->flags & NE_FFLAGS_SELFLOAD)
427 HFILE hf;
428 HFILE16 hFile16;
429 HGLOBAL16 sel;
430 /* Handle self-loading modules */
431 SELFLOADHEADER *selfloadheader;
432 HMODULE16 mod = GetModuleHandle16("KERNEL");
433 DWORD oldstack;
435 TRACE_(module)("%.*s is a self-loading module!\n",
436 *((BYTE*)pModule + pModule->name_table),
437 (char *)pModule + pModule->name_table + 1);
438 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
439 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) );
440 selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc");
441 selfloadheader->MyAlloc = GetProcAddress16(mod,"MyAlloc");
442 selfloadheader->SetOwner = GetProcAddress16(mod,"FarSetOwner");
443 sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 );
444 pModule->self_loading_sel = SEL(sel);
445 FarSetOwner16( sel, pModule->self );
446 oldstack = NtCurrentTeb()->cur_stack;
447 NtCurrentTeb()->cur_stack = MAKESEGPTR(pModule->self_loading_sel,
448 0xff00 - sizeof(STACK16FRAME) );
450 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule),
451 GetCurrentProcess(), &hf, 0, FALSE, DUPLICATE_SAME_ACCESS );
452 hFile16 = Win32HandleToDosFileHandle( hf );
453 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
454 pModule->self,hFile16);
455 NE_CallTo16_word_ww(selfloadheader->BootApp, pModule->self,hFile16);
456 TRACE_(dll)("Return from CallBootAppProc\n");
457 _lclose16(hf);
458 NtCurrentTeb()->cur_stack = oldstack;
460 for (i = 2; i <= pModule->seg_count; i++)
461 if (!NE_LoadSegment( pModule, i )) return FALSE;
463 else
465 for (i = 1; i <= pModule->seg_count; i++)
466 if (!NE_LoadSegment( pModule, i )) return FALSE;
468 return TRUE;
472 /***********************************************************************
473 * NE_FixupSegmentPrologs
475 * Fixup exported functions prologs of one segment
477 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
479 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
480 ET_BUNDLE *bundle;
481 ET_ENTRY *entry;
482 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
483 BYTE *pSeg, *pFunc;
485 TRACE_(module)("(%d);\n", segnum);
487 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
489 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
490 return;
493 if (!pModule->dgroup) return;
495 if (!(dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg))) return;
497 pSeg = MapSL( MAKESEGPTR(sel, 0) );
499 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);
501 do {
502 TRACE_(module)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
503 if (!(num_entries = bundle->last - bundle->first))
504 return;
505 entry = (ET_ENTRY *)((BYTE *)bundle+6);
506 while (num_entries--)
508 /*TRACE_(module)("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
509 if (entry->segnum == segnum)
511 pFunc = ((BYTE *)pSeg+entry->offs);
512 TRACE_(module)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
513 if (*(pFunc+2) == 0x90)
515 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
517 TRACE_(module)("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
518 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
521 if (*(WORD *)pFunc == 0xd88c)
523 if ((entry->flags & 2)) /* public data ? */
525 TRACE_(module)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
526 *pFunc = 0xb8; /* mov ax, */
527 *(WORD *)(pFunc+1) = dgroup;
529 else
530 if ((pModule->flags & NE_FFLAGS_MULTIPLEDATA)
531 && (entry->flags & 1)) /* exported ? */
533 TRACE_(module)("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
534 *(WORD *)pFunc = 0x9090; /* nop, nop */
539 entry++;
541 } while ( (bundle->next)
542 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
546 /***********************************************************************
547 * PatchCodeHandle
549 * Needed for self-loading modules.
551 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
553 WORD segnum;
554 WORD sel = SEL(hSeg);
555 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
556 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
558 TRACE_(module)("(%04x);\n", hSeg);
560 /* find the segment number of the module that belongs to hSeg */
561 for (segnum = 1; segnum <= pModule->seg_count; segnum++)
563 if (SEL(pSegTable[segnum-1].hSeg) == sel)
565 NE_FixupSegmentPrologs(pModule, segnum);
566 break;
570 return MAKELONG(hSeg, sel);
574 /***********************************************************************
575 * NE_GetDLLInitParams
577 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
578 WORD *hInst, WORD *ds, WORD *heap )
580 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
582 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
584 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
586 /* Not SINGLEDATA */
587 ERR_(dll)("Library is not marked SINGLEDATA\n");
588 exit(1);
590 else /* DATA NONE DLL */
592 *ds = 0;
593 *heap = 0;
596 else /* DATA SINGLE DLL */
598 if (pModule->dgroup) {
599 *ds = SEL(pSegTable[pModule->dgroup-1].hSeg);
600 *heap = pModule->heap_size;
602 else /* hmm, DLL has no dgroup,
603 but why has it NE_FFLAGS_SINGLEDATA set ?
604 Buggy DLL compiler ? */
606 *ds = 0;
607 *heap = 0;
611 *hInst = *ds ? GlobalHandle16(*ds) : pModule->self;
615 /***********************************************************************
616 * NE_InitDLL
618 * Call the DLL initialization code
620 static BOOL NE_InitDLL( NE_MODULE *pModule )
622 SEGTABLEENTRY *pSegTable;
623 WORD hInst, ds, heap;
624 CONTEXT86 context;
626 pSegTable = NE_SEG_TABLE( pModule );
628 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
629 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
631 /* Call USER signal handler for Win3.1 compatibility. */
632 TASK_CallTaskSignalProc( USIG16_DLL_LOAD, pModule->self );
634 if (!pModule->cs) return TRUE; /* no initialization code */
637 /* Registers at initialization must be:
638 * cx heap size
639 * di library instance
640 * ds data segment if any
641 * es:si command line (always 0)
644 memset( &context, 0, sizeof(context) );
646 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
648 context.Ecx = heap;
649 context.Edi = hInst;
650 context.SegDs = ds;
651 context.SegEs = ds; /* who knows ... */
653 context.SegCs = SEL(pSegTable[pModule->cs-1].hSeg);
654 context.Eip = pModule->ip;
655 context.Ebp = OFFSETOF(NtCurrentTeb()->cur_stack) + (WORD)&((STACK16FRAME*)0)->bp;
658 pModule->cs = 0; /* Don't initialize it twice */
659 TRACE_(dll)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
660 context.SegCs, context.Eip, context.SegDs,
661 LOWORD(context.Edi), LOWORD(context.Ecx) );
662 wine_call_to_16_regs_short( &context, 0 );
663 return TRUE;
666 /***********************************************************************
667 * NE_InitializeDLLs
669 * Recursively initialize all DLLs (according to the order in which
670 * they where loaded).
672 void NE_InitializeDLLs( HMODULE16 hModule )
674 NE_MODULE *pModule;
675 HMODULE16 *pDLL;
677 if (!(pModule = NE_GetPtr( hModule ))) return;
678 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
680 if (pModule->dlls_to_init)
682 HGLOBAL16 to_init = pModule->dlls_to_init;
683 pModule->dlls_to_init = 0;
684 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
686 NE_InitializeDLLs( *pDLL );
688 GlobalFree16( to_init );
690 NE_InitDLL( pModule );
694 /***********************************************************************
695 * NE_CallDllEntryPoint
697 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
699 typedef DWORD WINAPI (*WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
701 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
703 WORD hInst, ds, heap;
704 FARPROC16 entryPoint;
706 if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) return;
707 if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
708 if (!(entryPoint = GetProcAddress16( pModule->self, "DllEntryPoint" ))) return;
710 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
712 TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
713 NE_MODULE_NAME( pModule ),
714 SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
716 if ( pModule->flags & NE_FFLAGS_BUILTIN )
718 WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target;
720 entryProc( dwReason, hInst, ds, heap, 0, 0 );
722 else
724 LPBYTE stack = (LPBYTE)CURRENT_STACK16;
725 CONTEXT86 context;
727 memset( &context, 0, sizeof(context) );
728 context.SegDs = ds;
729 context.SegEs = ds; /* who knows ... */
731 context.SegCs = HIWORD(entryPoint);
732 context.Eip = LOWORD(entryPoint);
733 context.Ebp = OFFSETOF( NtCurrentTeb()->cur_stack )
734 + (WORD)&((STACK16FRAME*)0)->bp;
736 *(DWORD *)(stack - 4) = dwReason; /* dwReason */
737 *(WORD *) (stack - 6) = hInst; /* hInst */
738 *(WORD *) (stack - 8) = ds; /* wDS */
739 *(WORD *) (stack - 10) = heap; /* wHeapSize */
740 *(DWORD *)(stack - 14) = 0; /* dwReserved1 */
741 *(WORD *) (stack - 16) = 0; /* wReserved2 */
743 wine_call_to_16_regs_short( &context, 16 );
747 /***********************************************************************
748 * NE_DllProcessAttach
750 * Call the DllEntryPoint of all modules this one (recursively)
751 * depends on, according to the order in which they were loaded.
753 * Note that --as opposed to the PE module case-- there is no notion
754 * of 'module loaded into a process' for NE modules, and hence we
755 * have no place to store the fact that the DllEntryPoint of a
756 * given module was already called on behalf of this process (e.g.
757 * due to some earlier LoadLibrary16 call).
759 * Thus, we just call the DllEntryPoint twice in that case. Win9x
760 * appears to behave this way as well ...
762 * This routine must only be called with the Win16Lock held.
764 * FIXME: We should actually abort loading in case the DllEntryPoint
765 * returns FALSE ...
769 struct ne_init_list
771 int count;
772 int size;
773 NE_MODULE **module;
776 static void add_to_init_list( struct ne_init_list *list, NE_MODULE *hModule )
778 if ( list->count == list->size )
780 int newSize = list->size + 128;
781 NE_MODULE **newModule = HeapReAlloc( GetProcessHeap(), 0,
782 list->module, newSize*sizeof(NE_MODULE *) );
783 if ( !newModule )
785 FIXME_(dll)("Out of memory!");
786 return;
789 list->module = newModule;
790 list->size = newSize;
793 list->module[list->count++] = hModule;
796 static void free_init_list( struct ne_init_list *list )
798 if ( list->module )
800 HeapFree( GetProcessHeap(), 0, list->module );
801 memset( list, 0, sizeof(*list) );
805 static void fill_init_list( struct ne_init_list *list, HMODULE16 hModule )
807 NE_MODULE *pModule;
808 WORD *pModRef;
809 int i;
811 if (!(pModule = NE_GetPtr( hModule ))) return;
812 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
814 /* Never add a module twice */
815 for ( i = 0; i < list->count; i++ )
816 if ( list->module[i] == pModule )
817 return;
819 /* Check for recursive call */
820 if ( pModule->misc_flags & 0x80 ) return;
822 TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
824 /* Tag current module to prevent recursive loop */
825 pModule->misc_flags |= 0x80;
827 /* Recursively attach all DLLs this one depends on */
828 pModRef = NE_MODULE_TABLE( pModule );
829 for ( i = 0; i < pModule->modref_count; i++ )
830 if ( pModRef[i] )
831 fill_init_list( list, (HMODULE16)pModRef[i] );
833 /* Add current module */
834 add_to_init_list( list, pModule );
836 /* Remove recursion flag */
837 pModule->misc_flags &= ~0x80;
839 TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
842 static void call_init_list( struct ne_init_list *list )
844 int i;
845 for ( i = 0; i < list->count; i++ )
846 NE_CallDllEntryPoint( list->module[i], DLL_PROCESS_ATTACH );
849 void NE_DllProcessAttach( HMODULE16 hModule )
851 struct ne_init_list list;
852 memset( &list, 0, sizeof(list) );
854 fill_init_list( &list, hModule );
855 call_init_list( &list );
856 free_init_list( &list );
860 /***********************************************************************
861 * NE_Ne2MemFlags
863 * This function translates NE segment flags to GlobalAlloc flags
865 static WORD NE_Ne2MemFlags(WORD flags)
867 WORD memflags = 0;
868 #if 1
869 if (flags & NE_SEGFLAGS_DISCARDABLE)
870 memflags |= GMEM_DISCARDABLE;
871 if (flags & NE_SEGFLAGS_MOVEABLE ||
872 ( ! (flags & NE_SEGFLAGS_DATA) &&
873 ! (flags & NE_SEGFLAGS_LOADED) &&
874 ! (flags & NE_SEGFLAGS_ALLOCATED)
877 memflags |= GMEM_MOVEABLE;
878 memflags |= GMEM_ZEROINIT;
879 #else
880 memflags = GMEM_ZEROINIT | GMEM_FIXED;
881 #endif
882 return memflags;
885 /***********************************************************************
886 * MyAlloc16 (KERNEL Wine-specific export)
888 * MyAlloc() function for self-loading apps.
890 DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
892 WORD size = wSize << wElem;
893 HANDLE16 hMem = 0;
895 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
896 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
898 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
899 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
901 WORD hSel = SEL(hMem);
902 WORD access = SelectorAccessRights16(hSel,0,0);
904 access |= 2<<2; /* SEGMENT_CODE */
905 SelectorAccessRights16(hSel,1,access);
907 if (size)
908 return MAKELONG( hMem, SEL(hMem) );
909 else
910 return MAKELONG( 0, hMem );
913 /***********************************************************************
914 * NE_GetInstance
916 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
918 if ( !pModule->dgroup )
919 return pModule->self;
920 else
922 SEGTABLEENTRY *pSeg;
923 pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
924 return pSeg->hSeg;
928 /***********************************************************************
929 * NE_CreateSegment
931 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
933 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
934 int minsize;
935 unsigned char selflags;
937 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
939 if ( segnum < 1 || segnum > pModule->seg_count )
940 return FALSE;
942 if ( (pModule->flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
943 return TRUE; /* selfloader allocates segment itself */
945 if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->dgroup )
946 return TRUE; /* all but DGROUP only allocated once */
948 minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
949 if ( segnum == pModule->ss ) minsize += pModule->stack_size;
950 if ( segnum == pModule->dgroup ) minsize += pModule->heap_size;
952 selflags = (pSeg->flags & NE_SEGFLAGS_DATA) ? WINE_LDT_FLAGS_DATA : WINE_LDT_FLAGS_CODE;
953 if (pSeg->flags & NE_SEGFLAGS_32BIT) selflags |= WINE_LDT_FLAGS_32BIT;
954 pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags), minsize, pModule->self, selflags );
955 if (!pSeg->hSeg) return FALSE;
957 pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
958 return TRUE;
961 /***********************************************************************
962 * NE_CreateAllSegments
964 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
966 int i;
967 for ( i = 1; i <= pModule->seg_count; i++ )
968 if ( !NE_CreateSegment( pModule, i ) )
969 return FALSE;
971 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
972 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
973 return TRUE;
977 /**********************************************************************
978 * IsSharedSelector (KERNEL.345)
980 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
982 /* Check whether the selector belongs to a DLL */
983 NE_MODULE *pModule = NE_GetPtr( selector );
984 if (!pModule) return FALSE;
985 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;