Use __ASM_GLOBAL_FUNC directly in i386-only code.
[wine/multimedia.git] / loader / ne / segment.c
blob2b780dbb7901096e2306b6c12d09f4cb44e1e985
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 "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 = (SELFLOADHEADER *)
145 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg),0);
146 oldstack = NtCurrentTeb()->cur_stack;
147 NtCurrentTeb()->cur_stack = PTR_SEG_OFF_TO_SEGPTR(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)PTR_SEG_OFF_TO_SEGPTR( 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 = PTR_SEG_OFF_TO_LIN( 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 = PTR_SEG_OFF_TO_LIN( 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 /* 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 = (SELFLOADHEADER *)
439 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg), 0);
440 selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc");
441 selfloadheader->MyAlloc = GetProcAddress16(mod,"MyAlloc");
442 selfloadheader->SetOwner = GetProcAddress16(mod,"FarSetOwner");
443 pModule->self_loading_sel = SEL(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, WINE_LDT_FLAGS_DATA));
444 oldstack = NtCurrentTeb()->cur_stack;
445 NtCurrentTeb()->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
446 0xff00 - sizeof(STACK16FRAME) );
448 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule),
449 GetCurrentProcess(), &hf, 0, FALSE, DUPLICATE_SAME_ACCESS );
450 hFile16 = Win32HandleToDosFileHandle( hf );
451 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
452 pModule->self,hFile16);
453 NE_CallTo16_word_ww(selfloadheader->BootApp, pModule->self,hFile16);
454 TRACE_(dll)("Return from CallBootAppProc\n");
455 _lclose16(hf);
456 NtCurrentTeb()->cur_stack = oldstack;
458 for (i = 2; i <= pModule->seg_count; i++)
459 if (!NE_LoadSegment( pModule, i )) return FALSE;
461 else
463 for (i = 1; i <= pModule->seg_count; i++)
464 if (!NE_LoadSegment( pModule, i )) return FALSE;
466 return TRUE;
470 /***********************************************************************
471 * NE_FixupSegmentPrologs
473 * Fixup exported functions prologs of one segment
475 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
477 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
478 ET_BUNDLE *bundle;
479 ET_ENTRY *entry;
480 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
481 BYTE *pSeg, *pFunc;
483 TRACE_(module)("(%d);\n", segnum);
485 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
487 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
488 return;
491 if (!pModule->dgroup) return;
493 if (!(dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg))) return;
495 pSeg = PTR_SEG_OFF_TO_LIN(sel, 0);
497 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);
499 do {
500 TRACE_(module)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
501 if (!(num_entries = bundle->last - bundle->first))
502 return;
503 entry = (ET_ENTRY *)((BYTE *)bundle+6);
504 while (num_entries--)
506 /*TRACE_(module)("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
507 if (entry->segnum == segnum)
509 pFunc = ((BYTE *)pSeg+entry->offs);
510 TRACE_(module)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
511 if (*(pFunc+2) == 0x90)
513 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
515 TRACE_(module)("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
516 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
519 if (*(WORD *)pFunc == 0xd88c)
521 if ((entry->flags & 2)) /* public data ? */
523 TRACE_(module)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
524 *pFunc = 0xb8; /* mov ax, */
525 *(WORD *)(pFunc+1) = dgroup;
527 else
528 if ((pModule->flags & NE_FFLAGS_MULTIPLEDATA)
529 && (entry->flags & 1)) /* exported ? */
531 TRACE_(module)("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
532 *(WORD *)pFunc = 0x9090; /* nop, nop */
537 entry++;
539 } while ( (bundle->next)
540 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
544 /***********************************************************************
545 * PatchCodeHandle
547 * Needed for self-loading modules.
549 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
551 WORD segnum;
552 WORD sel = SEL(hSeg);
553 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
554 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
556 TRACE_(module)("(%04x);\n", hSeg);
558 /* find the segment number of the module that belongs to hSeg */
559 for (segnum = 1; segnum <= pModule->seg_count; segnum++)
561 if (SEL(pSegTable[segnum-1].hSeg) == sel)
563 NE_FixupSegmentPrologs(pModule, segnum);
564 break;
568 return MAKELONG(hSeg, sel);
572 /***********************************************************************
573 * NE_GetDLLInitParams
575 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
576 WORD *hInst, WORD *ds, WORD *heap )
578 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
580 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
582 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
584 /* Not SINGLEDATA */
585 ERR_(dll)("Library is not marked SINGLEDATA\n");
586 exit(1);
588 else /* DATA NONE DLL */
590 *ds = 0;
591 *heap = 0;
594 else /* DATA SINGLE DLL */
596 if (pModule->dgroup) {
597 *ds = SEL(pSegTable[pModule->dgroup-1].hSeg);
598 *heap = pModule->heap_size;
600 else /* hmm, DLL has no dgroup,
601 but why has it NE_FFLAGS_SINGLEDATA set ?
602 Buggy DLL compiler ? */
604 *ds = 0;
605 *heap = 0;
609 *hInst = *ds ? GlobalHandle16(*ds) : pModule->self;
613 /***********************************************************************
614 * NE_InitDLL
616 * Call the DLL initialization code
618 static BOOL NE_InitDLL( TDB* pTask, NE_MODULE *pModule )
620 SEGTABLEENTRY *pSegTable;
621 WORD hInst, ds, heap;
622 CONTEXT86 context;
624 pSegTable = NE_SEG_TABLE( pModule );
626 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
627 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
629 /* Call USER signal handler for Win3.1 compatibility. */
630 TASK_CallTaskSignalProc( USIG16_DLL_LOAD, pModule->self );
632 if (!pModule->cs) return TRUE; /* no initialization code */
635 /* Registers at initialization must be:
636 * cx heap size
637 * di library instance
638 * ds data segment if any
639 * es:si command line (always 0)
642 memset( &context, 0, sizeof(context) );
644 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
646 context.Ecx = heap;
647 context.Edi = hInst;
648 context.SegDs = ds;
649 context.SegEs = ds; /* who knows ... */
651 context.SegCs = SEL(pSegTable[pModule->cs-1].hSeg);
652 context.Eip = pModule->ip;
653 context.Ebp = OFFSETOF(NtCurrentTeb()->cur_stack) + (WORD)&((STACK16FRAME*)0)->bp;
656 pModule->cs = 0; /* Don't initialize it twice */
657 TRACE_(dll)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
658 context.SegCs, context.Eip, context.SegDs,
659 LOWORD(context.Edi), LOWORD(context.Ecx) );
660 wine_call_to_16_regs_short( &context, 0 );
661 return TRUE;
664 /***********************************************************************
665 * NE_InitializeDLLs
667 * Recursively initialize all DLLs (according to the order in which
668 * they where loaded).
670 void NE_InitializeDLLs( HMODULE16 hModule )
672 TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
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( pTask, 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)
718 ((ENTRYPOINT16 *)PTR_SEG_TO_LIN( 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 ...
768 void NE_DllProcessAttach( HMODULE16 hModule )
770 NE_MODULE *pModule;
771 WORD *pModRef;
772 int i;
774 if (!(pModule = NE_GetPtr( hModule ))) return;
775 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
777 /* Check for recursive call */
778 if ( pModule->misc_flags & 0x80 ) return;
780 TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
782 /* Tag current module to prevent recursive loop */
783 pModule->misc_flags |= 0x80;
785 /* Recursively attach all DLLs this one depends on */
786 pModRef = NE_MODULE_TABLE( pModule );
787 for ( i = 0; i < pModule->modref_count; i++ )
788 if ( pModRef[i] )
789 NE_DllProcessAttach( (HMODULE16)pModRef[i] );
791 /* Call DLL entry point */
792 NE_CallDllEntryPoint( pModule, DLL_PROCESS_ATTACH );
794 /* Remove recursion flag */
795 pModule->misc_flags &= ~0x80;
797 TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
801 /***********************************************************************
802 * NE_Ne2MemFlags
804 * This function translates NE segment flags to GlobalAlloc flags
806 static WORD NE_Ne2MemFlags(WORD flags)
808 WORD memflags = 0;
809 #if 1
810 if (flags & NE_SEGFLAGS_DISCARDABLE)
811 memflags |= GMEM_DISCARDABLE;
812 if (flags & NE_SEGFLAGS_MOVEABLE ||
813 ( ! (flags & NE_SEGFLAGS_DATA) &&
814 ! (flags & NE_SEGFLAGS_LOADED) &&
815 ! (flags & NE_SEGFLAGS_ALLOCATED)
818 memflags |= GMEM_MOVEABLE;
819 memflags |= GMEM_ZEROINIT;
820 #else
821 memflags = GMEM_ZEROINIT | GMEM_FIXED;
822 #endif
823 return memflags;
826 /***********************************************************************
827 * MyAlloc16 (KERNEL Wine-specific export)
829 * MyAlloc() function for self-loading apps.
831 DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
833 WORD size = wSize << wElem;
834 HANDLE16 hMem = 0;
836 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
837 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
839 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
840 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
842 WORD hSel = SEL(hMem);
843 WORD access = SelectorAccessRights16(hSel,0,0);
845 access |= 2<<2; /* SEGMENT_CODE */
846 SelectorAccessRights16(hSel,1,access);
848 if (size)
849 return MAKELONG( hMem, SEL(hMem) );
850 else
851 return MAKELONG( 0, hMem );
854 /***********************************************************************
855 * NE_GetInstance
857 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
859 if ( !pModule->dgroup )
860 return pModule->self;
861 else
863 SEGTABLEENTRY *pSeg;
864 pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
865 return pSeg->hSeg;
869 /***********************************************************************
870 * NE_CreateSegment
872 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
874 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
875 int minsize;
876 unsigned char selflags;
878 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
880 if ( segnum < 1 || segnum > pModule->seg_count )
881 return FALSE;
883 if ( (pModule->flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
884 return TRUE; /* selfloader allocates segment itself */
886 if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->dgroup )
887 return TRUE; /* all but DGROUP only allocated once */
889 minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
890 if ( segnum == pModule->ss ) minsize += pModule->stack_size;
891 if ( segnum == pModule->dgroup ) minsize += pModule->heap_size;
893 selflags = (pSeg->flags & NE_SEGFLAGS_DATA) ? WINE_LDT_FLAGS_DATA : WINE_LDT_FLAGS_CODE;
894 if (pSeg->flags & NE_SEGFLAGS_32BIT) selflags |= WINE_LDT_FLAGS_32BIT;
895 pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags), minsize, pModule->self, selflags );
896 if (!pSeg->hSeg) return FALSE;
898 pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
899 return TRUE;
902 /***********************************************************************
903 * NE_CreateAllSegments
905 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
907 int i;
908 for ( i = 1; i <= pModule->seg_count; i++ )
909 if ( !NE_CreateSegment( pModule, i ) )
910 return FALSE;
912 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
913 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
914 return TRUE;
918 /**********************************************************************
919 * IsSharedSelector (KERNEL.345)
921 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
923 /* Check whether the selector belongs to a DLL */
924 NE_MODULE *pModule = NE_GetPtr( selector );
925 if (!pModule) return FALSE;
926 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;