kernel32/tests/pipe: Enable compilation with long types.
[wine.git] / dlls / krnl386.exe16 / ne_segment.c
blob3eb8bae2ff3961af858b608a9544eb875df1c530
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <fcntl.h>
26 #include <ctype.h>
27 #include <string.h>
29 #include "wine/winbase16.h"
30 #include "wownt32.h"
31 #include "winternl.h"
32 #include "kernel16_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(fixup);
36 WINE_DECLARE_DEBUG_CHANNEL(dll);
37 WINE_DECLARE_DEBUG_CHANNEL(module);
40 * Relocation table entry
42 struct relocation_entry_s
44 BYTE address_type; /* Relocation address type */
45 BYTE relocation_type; /* Relocation type */
46 WORD offset; /* Offset in segment to fixup */
47 WORD target1; /* Target specification */
48 WORD target2; /* Target specification */
52 * Relocation address types
54 #define NE_RADDR_LOWBYTE 0
55 #define NE_RADDR_SELECTOR 2
56 #define NE_RADDR_POINTER32 3
57 #define NE_RADDR_OFFSET16 5
58 #define NE_RADDR_POINTER48 11
59 #define NE_RADDR_OFFSET32 13
62 * Relocation types
64 #define NE_RELTYPE_INTERNAL 0
65 #define NE_RELTYPE_ORDINAL 1
66 #define NE_RELTYPE_NAME 2
67 #define NE_RELTYPE_OSFIXUP 3
68 #define NE_RELFLAG_ADDITIVE 4
70 /* Self-loading modules contain this structure in their first segment */
71 typedef struct
73 WORD version; /* Must be "A0" (0x3041) */
74 WORD reserved;
75 FARPROC16 BootApp; /* startup procedure */
76 FARPROC16 LoadAppSeg; /* procedure to load a segment */
77 FARPROC16 reserved2;
78 FARPROC16 MyAlloc; /* memory allocation procedure,
79 * wine must write this field */
80 FARPROC16 EntryAddrProc;
81 FARPROC16 ExitProc; /* exit procedure */
82 WORD reserved3[4];
83 FARPROC16 SetOwner; /* Set Owner procedure, exported by wine */
84 } SELFLOADHEADER;
86 #define SEL(x) ((x)|1)
88 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);
91 /***********************************************************************
92 * NE_GetRelocAddrName
94 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
96 switch(addr_type & 0x7f)
98 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
99 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
100 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
101 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
102 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
103 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
105 return "???";
109 /***********************************************************************
110 * NE_OpenFile
112 static HFILE16 NE_OpenFile( NE_MODULE *pModule )
114 char *name = NE_MODULE_NAME( pModule );
115 HANDLE handle = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
116 NULL, OPEN_EXISTING, 0, 0 );
118 if (handle == INVALID_HANDLE_VALUE)
120 ERR( "Can't open file '%s' for module %04x\n", name, pModule->self );
121 return HFILE_ERROR;
123 return Win32HandleToDosFileHandle( handle );
127 /***********************************************************************
128 * apply_relocations
130 * Apply relocations to a segment. Helper for NE_LoadSegment.
132 static inline BOOL apply_relocations( NE_MODULE *pModule, const struct relocation_entry_s *rep,
133 int count, int segnum )
135 BYTE *func_name;
136 char buffer[256];
137 int i, ordinal;
138 WORD offset, *sp;
139 HMODULE16 module;
140 FARPROC16 address = 0;
141 HMODULE16 *pModuleTable = (HMODULE16 *)((char *)pModule + pModule->ne_modtab);
142 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
143 SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;
146 * Go through the relocation table one entry at a time.
148 for (i = 0; i < count; i++, rep++)
151 * Get the target address corresponding to this entry.
154 /* If additive, there is no target chain list. Instead, add source
155 and target */
156 int additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
157 switch (rep->relocation_type & 3)
159 case NE_RELTYPE_ORDINAL:
160 module = pModuleTable[rep->target1-1];
161 ordinal = rep->target2;
162 address = NE_GetEntryPoint( module, ordinal );
163 if (!address)
165 NE_MODULE *pTarget = NE_GetPtr( module );
166 if (!pTarget)
167 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
168 module, rep->target1,
169 *((BYTE *)pModule + pModule->ne_restab),
170 *((BYTE *)pModule + pModule->ne_restab),
171 (char *)pModule + pModule->ne_restab + 1 );
172 else
174 ERR("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
175 *((BYTE *)pTarget + pTarget->ne_restab),
176 (char *)pTarget + pTarget->ne_restab + 1,
177 ordinal );
178 address = (FARPROC16)0xdeadbeef;
181 if (TRACE_ON(fixup))
183 NE_MODULE *pTarget = NE_GetPtr( module );
184 TRACE("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
185 *((BYTE *)pTarget + pTarget->ne_restab),
186 (char *)pTarget + pTarget->ne_restab + 1,
187 ordinal, HIWORD(address), LOWORD(address),
188 NE_GetRelocAddrName( rep->address_type, additive ) );
190 break;
192 case NE_RELTYPE_NAME:
193 module = pModuleTable[rep->target1-1];
194 func_name = (BYTE *)pModule + pModule->ne_imptab + rep->target2;
195 memcpy( buffer, func_name+1, *func_name );
196 buffer[*func_name] = '\0';
197 ordinal = NE_GetOrdinal( module, buffer );
198 address = NE_GetEntryPoint( module, ordinal );
200 if (ERR_ON(fixup) && !address)
202 NE_MODULE *pTarget = NE_GetPtr( module );
203 ERR("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
204 *((BYTE *)pTarget + pTarget->ne_restab),
205 (char *)pTarget + pTarget->ne_restab + 1, buffer );
207 if (!address) address = (FARPROC16) 0xdeadbeef;
208 if (TRACE_ON(fixup))
210 NE_MODULE *pTarget = NE_GetPtr( module );
211 TRACE("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
212 *((BYTE *)pTarget + pTarget->ne_restab),
213 (char *)pTarget + pTarget->ne_restab + 1,
214 buffer, HIWORD(address), LOWORD(address),
215 NE_GetRelocAddrName( rep->address_type, additive ) );
217 break;
219 case NE_RELTYPE_INTERNAL:
220 if ((rep->target1 & 0xff) == 0xff)
222 address = NE_GetEntryPoint( pModule->self, rep->target2 );
224 else
226 address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
229 TRACE("%d: %04x:%04x %s\n",
230 i + 1, HIWORD(address), LOWORD(address),
231 NE_GetRelocAddrName( rep->address_type, additive ) );
232 break;
234 case NE_RELTYPE_OSFIXUP:
235 /* Relocation type 7:
237 * These appear to be used as fixups for the Windows
238 * floating point emulator. Let's just ignore them and
239 * try to use the hardware floating point. Linux should
240 * successfully emulate the coprocessor if it doesn't
241 * exist.
243 TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
244 i + 1, rep->relocation_type, rep->offset,
245 rep->target1, rep->target2,
246 NE_GetRelocAddrName( rep->address_type, additive ) );
247 continue;
250 offset = rep->offset;
252 /* Apparently, high bit of address_type is sometimes set; */
253 /* we ignore it for now */
254 if (rep->address_type > NE_RADDR_OFFSET32)
256 char module[10];
257 GetModuleName16( pModule->self, module, sizeof(module) );
258 ERR("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
259 module, rep->address_type );
262 if (additive)
264 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
265 TRACE(" %04x:%04x\n", offset, *sp );
266 switch (rep->address_type & 0x7f)
268 case NE_RADDR_LOWBYTE:
269 *(BYTE *)sp += LOBYTE((int)address);
270 break;
271 case NE_RADDR_OFFSET16:
272 *sp += LOWORD(address);
273 break;
274 case NE_RADDR_POINTER32:
275 *sp += LOWORD(address);
276 *(sp+1) = HIWORD(address);
277 break;
278 case NE_RADDR_SELECTOR:
279 /* Borland creates additive records with offset zero. Strange, but OK */
280 if (*sp)
281 ERR("Additive selector to %04x.Please report\n",*sp);
282 else
283 *sp = HIWORD(address);
284 break;
285 default:
286 goto unknown;
289 else /* non-additive fixup */
293 WORD next_offset;
295 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
296 next_offset = *sp;
297 TRACE(" %04x:%04x\n", offset, *sp );
298 switch (rep->address_type & 0x7f)
300 case NE_RADDR_LOWBYTE:
301 *(BYTE *)sp = LOBYTE((int)address);
302 break;
303 case NE_RADDR_OFFSET16:
304 *sp = LOWORD(address);
305 break;
306 case NE_RADDR_POINTER32:
307 *(FARPROC16 *)sp = address;
308 break;
309 case NE_RADDR_SELECTOR:
310 *sp = SELECTOROF(address);
311 break;
312 default:
313 goto unknown;
315 if (next_offset == offset) break; /* avoid infinite loop */
316 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
317 offset = next_offset;
318 } while (offset != 0xffff);
321 return TRUE;
323 unknown:
324 WARN("WARNING: %d: unknown ADDR TYPE %d, "
325 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
326 i + 1, rep->address_type, rep->relocation_type,
327 rep->offset, rep->target1, rep->target2);
328 return FALSE;
332 /***********************************************************************
333 * NE_LoadSegment
335 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
337 WORD count;
338 DWORD pos;
339 const struct relocation_entry_s *rep;
340 int size;
341 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
342 SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;
344 if (pSeg->flags & NE_SEGFLAGS_LOADED)
346 /* self-loader ? -> already loaded it */
347 if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
348 return TRUE;
350 /* leave, except for DGROUP, as this may be the second instance */
351 if (segnum != pModule->ne_autodata)
352 return TRUE;
355 if (!pSeg->filepos) return TRUE; /* No file image, just return */
357 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
358 segnum, pSeg->hSeg, pSeg->flags );
359 pos = pSeg->filepos << pModule->ne_align;
360 if (pSeg->size) size = pSeg->size;
361 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
363 if (pModule->ne_flags & NE_FFLAGS_SELFLOAD && segnum > 1)
365 /* Implement self-loading segments */
366 SELFLOADHEADER *selfloadheader;
367 WORD old_ss = CURRENT_SS, old_sp = CURRENT_SP;
368 HFILE16 hFile16;
369 WORD args[3];
370 DWORD ret;
372 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
373 CURRENT_SS = pModule->self_loading_sel;
374 CURRENT_SP = 0xff00 - sizeof(STACK16FRAME);
376 hFile16 = NE_OpenFile( pModule );
377 TRACE_(dll)("Call LoadAppSegProc(hmodule=0x%04x,hf=%x,segnum=%d)\n",
378 pModule->self,hFile16,segnum );
379 args[2] = pModule->self;
380 args[1] = hFile16;
381 args[0] = segnum;
382 WOWCallback16Ex( (DWORD)selfloadheader->LoadAppSeg, WCB16_PASCAL, sizeof(args), args, &ret );
383 pSeg->hSeg = LOWORD(ret);
384 TRACE_(dll)("Ret LoadAppSegProc: hSeg=0x%04x\n", pSeg->hSeg);
385 _lclose16( hFile16 );
386 CURRENT_SS = old_ss;
387 CURRENT_SP = old_sp;
389 pSeg->flags |= NE_SEGFLAGS_LOADED;
390 return TRUE;
392 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
394 void *mem = GlobalLock16(pSeg->hSeg);
395 if (!NE_READ_DATA( pModule, mem, pos, size ))
396 return FALSE;
397 pos += size;
399 else
402 The following bit of code for "iterated segments" was written without
403 any documentation on the format of these segments. It seems to work,
404 but may be missing something.
406 const char *buff = NE_GET_DATA( pModule, pos, size );
407 const char* curr = buff;
408 char *mem = GlobalLock16(pSeg->hSeg);
410 pos += size;
411 if (buff == NULL) return FALSE;
413 while(curr < buff + size) {
414 unsigned int rept = ((const short *)curr)[0];
415 unsigned int len = ((const short *)curr)[1];
417 curr += 2*sizeof(short);
418 while (rept--)
420 memcpy( mem, curr, len );
421 mem += len;
423 curr += len;
427 pSeg->flags |= NE_SEGFLAGS_LOADED;
429 /* Perform exported function prolog fixups */
430 NE_FixupSegmentPrologs( pModule, segnum );
432 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
433 return TRUE; /* No relocation data, we are done */
435 if (!NE_READ_DATA( pModule, &count, pos, sizeof(count) ) || !count) return TRUE;
436 pos += sizeof(count);
438 TRACE("Fixups for %.*s, segment %d, hSeg %04x\n",
439 *((BYTE *)pModule + pModule->ne_restab),
440 (char *)pModule + pModule->ne_restab + 1,
441 segnum, pSeg->hSeg );
443 if (!(rep = NE_GET_DATA( pModule, pos, count * sizeof(struct relocation_entry_s) )))
444 return FALSE;
446 return apply_relocations( pModule, rep, count, segnum );
450 /***********************************************************************
451 * NE_LoadAllSegments
453 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
455 int i;
456 SEGTABLEENTRY * pSegTable = NE_SEG_TABLE(pModule);
458 if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
460 HFILE16 hFile16;
461 HGLOBAL16 sel;
462 /* Handle self-loading modules */
463 SELFLOADHEADER *selfloadheader;
464 HMODULE16 mod = GetModuleHandle16("KERNEL");
465 WORD old_ss = CURRENT_SS, old_sp = CURRENT_SP;
466 WORD args[2];
468 TRACE_(module)("%.*s is a self-loading module!\n",
469 *((BYTE*)pModule + pModule->ne_restab),
470 (char *)pModule + pModule->ne_restab + 1);
471 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
472 selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) );
473 selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc");
474 selfloadheader->MyAlloc = GetProcAddress16(mod,"MyAlloc");
475 selfloadheader->SetOwner = GetProcAddress16(mod,"FarSetOwner");
476 sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 );
477 pModule->self_loading_sel = SEL(sel);
478 FarSetOwner16( sel, pModule->self );
479 CURRENT_SS = pModule->self_loading_sel;
480 CURRENT_SP = 0xff00 - sizeof(STACK16FRAME);
482 hFile16 = NE_OpenFile(pModule);
483 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
484 pModule->self,hFile16);
485 args[1] = pModule->self;
486 args[0] = hFile16;
487 WOWCallback16Ex( (DWORD)selfloadheader->BootApp, WCB16_PASCAL, sizeof(args), args, NULL );
488 TRACE_(dll)("Return from CallBootAppProc\n");
489 _lclose16(hFile16);
490 CURRENT_SS = old_ss;
491 CURRENT_SP = old_sp;
493 for (i = 2; i <= pModule->ne_cseg; i++)
494 if (!NE_LoadSegment( pModule, i )) return FALSE;
496 else
498 for (i = 1; i <= pModule->ne_cseg; i++)
499 if (!NE_LoadSegment( pModule, i )) return FALSE;
501 return TRUE;
505 /***********************************************************************
506 * NE_FixupSegmentPrologs
508 * Fixup exported functions prologs of one segment
510 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
512 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
513 ET_BUNDLE *bundle;
514 ET_ENTRY *entry;
515 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
516 BYTE *pSeg, *pFunc;
518 TRACE("(%d);\n", segnum);
520 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
522 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
523 return;
526 if (!pModule->ne_autodata) return;
528 if (!pSegTable[pModule->ne_autodata-1].hSeg) return;
529 dgroup = SEL(pSegTable[pModule->ne_autodata-1].hSeg);
531 pSeg = MapSL( MAKESEGPTR(sel, 0) );
533 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->ne_enttab);
535 do {
536 TRACE("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
537 if (!(num_entries = bundle->last - bundle->first))
538 return;
539 entry = (ET_ENTRY *)((BYTE *)bundle+6);
540 while (num_entries--)
542 /*TRACE("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
543 if (entry->segnum == segnum)
545 pFunc = pSeg+entry->offs;
546 TRACE("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
547 if (*(pFunc+2) == 0x90)
549 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
551 TRACE("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
552 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
555 if (*(WORD *)pFunc == 0xd88c)
557 if ((entry->flags & 2)) /* public data ? */
559 TRACE("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
560 *pFunc = 0xb8; /* mov ax, */
561 *(WORD *)(pFunc+1) = dgroup;
563 else if ((pModule->ne_flags & NE_FFLAGS_MULTIPLEDATA)
564 && (entry->flags & 1)) /* exported ? */
566 TRACE("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
567 *(WORD *)pFunc = 0x9090; /* nop, nop */
572 entry++;
574 } while ( (bundle->next) && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
578 /***********************************************************************
579 * PatchCodeHandle (KERNEL.110)
581 * Needed for self-loading modules.
583 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
585 WORD segnum;
586 WORD sel = SEL(hSeg);
587 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
588 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
590 TRACE_(module)("(%04x);\n", hSeg);
592 /* find the segment number of the module that belongs to hSeg */
593 for (segnum = 1; segnum <= pModule->ne_cseg; segnum++)
595 if (SEL(pSegTable[segnum-1].hSeg) == sel)
597 NE_FixupSegmentPrologs(pModule, segnum);
598 break;
602 return MAKELONG(hSeg, sel);
606 /***********************************************************************
607 * NE_GetDLLInitParams
609 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
610 WORD *hInst, WORD *ds, WORD *heap )
612 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
614 if (!(pModule->ne_flags & NE_FFLAGS_SINGLEDATA))
616 if (pModule->ne_flags & NE_FFLAGS_MULTIPLEDATA || pModule->ne_autodata)
618 /* Not SINGLEDATA */
619 ERR_(dll)("Library is not marked SINGLEDATA\n");
621 /* DATA NONE DLL */
622 *ds = 0;
623 *heap = 0;
625 else /* DATA SINGLE DLL */
627 if (pModule->ne_autodata) {
628 *ds = SEL(pSegTable[pModule->ne_autodata-1].hSeg);
629 *heap = pModule->ne_heap;
631 else /* hmm, DLL has no dgroup,
632 but why has it NE_FFLAGS_SINGLEDATA set ?
633 Buggy DLL compiler ? */
635 *ds = 0;
636 *heap = 0;
640 *hInst = *ds ? GlobalHandle16(*ds) : pModule->self;
644 /***********************************************************************
645 * NE_InitDLL
647 * Call the DLL initialization code
649 static BOOL NE_InitDLL( NE_MODULE *pModule )
651 SEGTABLEENTRY *pSegTable;
652 WORD hInst, ds, heap;
653 CONTEXT context;
655 pSegTable = NE_SEG_TABLE( pModule );
657 if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE) ||
658 (pModule->ne_flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
660 /* Call USER signal handler for Win3.1 compatibility. */
661 NE_CallUserSignalProc( pModule->self, USIG16_DLL_LOAD );
663 if (!SELECTOROF(pModule->ne_csip)) return TRUE; /* no initialization code */
666 /* Registers at initialization must be:
667 * cx heap size
668 * di library instance
669 * ds data segment if any
670 * es:si command line (always 0)
673 memset( &context, 0, sizeof(context) );
675 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
677 context.Ecx = heap;
678 context.Edi = hInst;
679 context.SegDs = ds;
680 context.SegEs = ds; /* who knows ... */
681 context.SegCs = SEL(pSegTable[SELECTOROF(pModule->ne_csip)-1].hSeg);
682 context.Eip = OFFSETOF(pModule->ne_csip);
683 context.Ebp = CURRENT_SP + FIELD_OFFSET(STACK16FRAME,bp);
685 pModule->ne_csip = 0; /* Don't initialize it twice */
686 TRACE_(dll)("Calling LibMain for %.*s, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
687 *((BYTE*)pModule + pModule->ne_restab),
688 (char *)pModule + pModule->ne_restab + 1,
689 context.SegCs, context.Eip, context.SegDs,
690 LOWORD(context.Edi), LOWORD(context.Ecx) );
691 WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)&context );
692 return TRUE;
695 /***********************************************************************
696 * NE_InitializeDLLs
698 * Recursively initialize all DLLs (according to the order in which
699 * they where loaded).
701 void NE_InitializeDLLs( HMODULE16 hModule )
703 NE_MODULE *pModule;
704 HMODULE16 *pDLL;
706 if (!(pModule = NE_GetPtr( hModule ))) return;
708 if (pModule->dlls_to_init)
710 HGLOBAL16 to_init = pModule->dlls_to_init;
711 pModule->dlls_to_init = 0;
712 for (pDLL = GlobalLock16( to_init ); *pDLL; pDLL++)
714 NE_InitializeDLLs( *pDLL );
716 GlobalFree16( to_init );
718 NE_InitDLL( pModule );
722 /**********************************************************************
723 * NE_CallUserSignalProc
725 * According to "Undocumented Windows", the task signal proc is
726 * bypassed for module load/unload notifications, and the USER signal
727 * proc is called directly instead. This is what this function does.
729 typedef DWORD (WINAPI *pSignalProc)( HANDLE16 module, UINT16 code, UINT16 exit,
730 HINSTANCE16 inst, HQUEUE16 queue );
732 void NE_CallUserSignalProc( HMODULE16 hModule, UINT16 code )
734 FARPROC16 proc;
735 HMODULE16 user = GetModuleHandle16("user.exe");
737 if (!user) return;
738 if ((proc = GetProcAddress16( user, "SignalProc" )))
740 /* USER is always a builtin dll */
741 pSignalProc sigproc = (pSignalProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)proc ))->target;
742 sigproc( hModule, code, 0, 0, 0 );
747 /***********************************************************************
748 * NE_CallDllEntryPoint
750 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
752 typedef DWORD (WINAPI *WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
754 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
756 WORD hInst, ds, heap;
757 FARPROC16 entryPoint;
759 if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE)) return;
760 if (!(pModule->ne_flags & NE_FFLAGS_BUILTIN) && pModule->ne_expver < 0x0400) return;
761 if (!(entryPoint = GetProcAddress16( pModule->self, "DllEntryPoint" ))) return;
763 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
765 TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
766 NE_MODULE_NAME( pModule ),
767 SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
769 if ( pModule->ne_flags & NE_FFLAGS_BUILTIN )
771 WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target;
773 entryProc( dwReason, hInst, ds, heap, 0, 0 );
775 else
777 CONTEXT context;
778 WORD args[8];
780 memset( &context, 0, sizeof(context) );
781 context.SegDs = ds;
782 context.SegEs = ds; /* who knows ... */
783 context.SegCs = HIWORD(entryPoint);
784 context.Eip = LOWORD(entryPoint);
785 context.Ebp = CURRENT_SP + FIELD_OFFSET(STACK16FRAME,bp);
787 args[7] = HIWORD(dwReason);
788 args[6] = LOWORD(dwReason);
789 args[5] = hInst;
790 args[4] = ds;
791 args[3] = heap;
792 args[2] = 0; /* HIWORD(dwReserved1) */
793 args[1] = 0; /* LOWORD(dwReserved1) */
794 args[0] = 0; /* wReserved2 */
795 WOWCallback16Ex( 0, WCB16_REGS, sizeof(args), args, (DWORD *)&context );
799 /***********************************************************************
800 * NE_DllProcessAttach
802 * Call the DllEntryPoint of all modules this one (recursively)
803 * depends on, according to the order in which they were loaded.
805 * Note that --as opposed to the PE module case-- there is no notion
806 * of 'module loaded into a process' for NE modules, and hence we
807 * have no place to store the fact that the DllEntryPoint of a
808 * given module was already called on behalf of this process (e.g.
809 * due to some earlier LoadLibrary16 call).
811 * Thus, we just call the DllEntryPoint twice in that case. Win9x
812 * appears to behave this way as well ...
814 * This routine must only be called with the Win16Lock held.
816 * FIXME: We should actually abort loading in case the DllEntryPoint
817 * returns FALSE ...
821 struct ne_init_list
823 int count;
824 int size;
825 NE_MODULE **module;
828 static void add_to_init_list( struct ne_init_list *list, NE_MODULE *hModule )
830 NE_MODULE **newModule = NULL;
831 if ( list->count == list->size )
833 int newSize = list->size + 128;
835 if (list->module)
836 newModule = HeapReAlloc( GetProcessHeap(), 0,
837 list->module, newSize*sizeof(NE_MODULE *) );
838 else
839 newModule = HeapAlloc( GetProcessHeap(), 0,
840 newSize*sizeof(NE_MODULE *) );
841 if ( !newModule )
843 FIXME_(dll)("Out of memory!\n");
844 return;
847 list->module = newModule;
848 list->size = newSize;
851 list->module[list->count++] = hModule;
854 static void free_init_list( struct ne_init_list *list )
856 if ( list->module )
858 HeapFree( GetProcessHeap(), 0, list->module );
859 memset( list, 0, sizeof(*list) );
863 static void fill_init_list( struct ne_init_list *list, HMODULE16 hModule )
865 NE_MODULE *pModule;
866 HMODULE16 *pModRef;
867 int i;
869 if (!(pModule = NE_GetPtr( hModule ))) return;
871 /* Never add a module twice */
872 for ( i = 0; i < list->count; i++ )
873 if ( list->module[i] == pModule )
874 return;
876 /* Check for recursive call */
877 if ( pModule->ne_flagsothers & 0x80 ) return;
879 TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
881 /* Tag current module to prevent recursive loop */
882 pModule->ne_flagsothers |= 0x80;
884 /* Recursively attach all DLLs this one depends on */
885 pModRef = (HMODULE16 *)((char *)pModule + pModule->ne_modtab);
886 for ( i = 0; i < pModule->ne_cmod; i++ )
887 if ( pModRef[i] ) fill_init_list( list, pModRef[i] );
889 /* Add current module */
890 add_to_init_list( list, pModule );
892 /* Remove recursion flag */
893 pModule->ne_flagsothers &= ~0x80;
895 TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
898 static void call_init_list( struct ne_init_list *list )
900 int i;
901 for ( i = 0; i < list->count; i++ )
902 NE_CallDllEntryPoint( list->module[i], DLL_PROCESS_ATTACH );
905 void NE_DllProcessAttach( HMODULE16 hModule )
907 struct ne_init_list list;
908 memset( &list, 0, sizeof(list) );
910 fill_init_list( &list, hModule );
911 call_init_list( &list );
912 free_init_list( &list );
916 /***********************************************************************
917 * NE_Ne2MemFlags
919 * This function translates NE segment flags to GlobalAlloc flags
921 static WORD NE_Ne2MemFlags(WORD flags)
923 WORD memflags = 0;
924 #if 1
925 if (flags & NE_SEGFLAGS_DISCARDABLE)
926 memflags |= GMEM_DISCARDABLE;
927 if (flags & NE_SEGFLAGS_MOVEABLE ||
928 ( ! (flags & NE_SEGFLAGS_DATA) &&
929 ! (flags & NE_SEGFLAGS_LOADED) &&
930 ! (flags & NE_SEGFLAGS_ALLOCATED)
933 memflags |= GMEM_MOVEABLE;
934 memflags |= GMEM_ZEROINIT;
935 #else
936 memflags = GMEM_ZEROINIT | GMEM_FIXED;
937 #endif
938 return memflags;
941 /***********************************************************************
942 * MyAlloc (KERNEL.668) Wine-specific export
944 * MyAlloc() function for self-loading apps.
946 DWORD WINAPI MyAlloc16( WORD wFlags, WORD wSize, WORD wElem )
948 WORD size = wSize << wElem;
949 HANDLE16 hMem = 0;
951 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
952 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
954 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
955 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
957 WORD hSel = SEL(hMem);
958 WORD access = SelectorAccessRights16(hSel,0,0);
960 access |= 2<<2; /* SEGMENT_CODE */
961 SelectorAccessRights16(hSel,1,access);
963 if (size)
964 return MAKELONG( hMem, SEL(hMem) );
965 else
966 return MAKELONG( 0, hMem );
969 /***********************************************************************
970 * NE_GetInstance
972 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
974 if ( !pModule->ne_autodata )
975 return pModule->self;
976 else
978 SEGTABLEENTRY *pSeg;
979 pSeg = NE_SEG_TABLE( pModule ) + pModule->ne_autodata - 1;
980 return pSeg->hSeg;
984 /***********************************************************************
985 * NE_CreateSegment
987 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
989 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
990 int minsize;
991 unsigned char selflags;
993 if ( segnum < 1 || segnum > pModule->ne_cseg )
994 return FALSE;
996 if ( (pModule->ne_flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
997 return TRUE; /* selfloader allocates segment itself */
999 if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->ne_autodata )
1000 return TRUE; /* all but DGROUP only allocated once */
1002 minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
1003 if ( segnum == SELECTOROF(pModule->ne_sssp) ) minsize += pModule->ne_stack;
1004 if ( segnum == pModule->ne_autodata ) minsize += pModule->ne_heap;
1006 selflags = (pSeg->flags & NE_SEGFLAGS_DATA) ? LDT_FLAGS_DATA : LDT_FLAGS_CODE;
1007 if (pSeg->flags & NE_SEGFLAGS_32BIT) selflags |= LDT_FLAGS_32BIT;
1008 pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags), minsize, pModule->self, selflags );
1009 if (!pSeg->hSeg) return FALSE;
1011 pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
1012 return TRUE;
1015 /***********************************************************************
1016 * NE_CreateAllSegments
1018 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
1020 int i;
1021 for ( i = 1; i <= pModule->ne_cseg; i++ )
1022 if ( !NE_CreateSegment( pModule, i ) )
1023 return FALSE;
1025 pModule->dgroup_entry = pModule->ne_autodata ? pModule->ne_segtab +
1026 (pModule->ne_autodata - 1) * sizeof(SEGTABLEENTRY) : 0;
1027 return TRUE;
1031 /**********************************************************************
1032 * IsSharedSelector (KERNEL.345)
1034 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
1036 /* Check whether the selector belongs to a DLL */
1037 NE_MODULE *pModule = NE_GetPtr( selector );
1038 if (!pModule) return FALSE;
1039 return (pModule->ne_flags & NE_FFLAGS_LIBMODULE) != 0;