4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
11 #include <sys/types.h>
18 #include "wine/winbase16.h"
19 #include "wine/library.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
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 /***********************************************************************
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";
91 /***********************************************************************
94 BOOL
NE_LoadSegment( NE_MODULE
*pModule
, WORD segnum
)
96 SEGTABLEENTRY
*pSegTable
, *pSeg
;
98 WORD count
, i
, offset
, next_offset
;
100 FARPROC16 address
= 0;
103 struct relocation_entry_s
*rep
, *reloc_entries
;
109 int ordinal
, additive
;
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
)
121 /* leave, except for DGROUP, as this may be the second instance */
122 if (segnum
!= pModule
->dgroup
)
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
;
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
);
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
);
174 WARN_(dll
)("Memory exausted!");
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
--) {
185 for(byte
= 0; byte
< len
; byte
++)
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!");
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" );
226 * Go through the relocation table one entry at a time.
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
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
);
248 NE_MODULE
*pTarget
= NE_GetPtr( module
);
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 );
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,
261 address
= (FARPROC16
)0xdeadbeef;
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
) );
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';
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;
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
) );
303 case NE_RELTYPE_INTERNAL
:
304 if ((rep
->target1
& 0xff) == 0xff)
306 address
= NE_GetEntryPoint( pModule
->self
, rep
->target2
);
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
) );
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
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
) );
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
)
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
);
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
);
355 case NE_RADDR_OFFSET16
:
356 *sp
+= LOWORD(address
);
358 case NE_RADDR_POINTER32
:
359 *sp
+= LOWORD(address
);
360 *(sp
+1) = HIWORD(address
);
362 case NE_RADDR_SELECTOR
:
363 /* Borland creates additive records with offset zero. Strange, but OK */
365 ERR_(fixup
)("Additive selector to %04x.Please report\n",*sp
);
367 *sp
= HIWORD(address
);
373 else /* non-additive fixup */
377 sp
= MapSL( MAKESEGPTR( SEL(pSeg
->hSeg
), offset
) );
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
);
385 case NE_RADDR_OFFSET16
:
386 *sp
= LOWORD(address
);
388 case NE_RADDR_POINTER32
:
389 *(FARPROC16
*)sp
= address
;
391 case NE_RADDR_SELECTOR
:
392 *sp
= SELECTOROF(address
);
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
);
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
);
417 /***********************************************************************
420 BOOL
NE_LoadAllSegments( NE_MODULE
*pModule
)
423 SEGTABLEENTRY
* pSegTable
= (SEGTABLEENTRY
*) NE_SEG_TABLE(pModule
);
425 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
430 /* Handle self-loading modules */
431 SELFLOADHEADER
*selfloadheader
;
432 HMODULE16 mod
= GetModuleHandle16("KERNEL");
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");
458 NtCurrentTeb()->cur_stack
= oldstack
;
460 for (i
= 2; i
<= pModule
->seg_count
; i
++)
461 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
465 for (i
= 1; i
<= pModule
->seg_count
; i
++)
466 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
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
);
482 WORD dgroup
, num_entries
, sel
= SEL(pSegTable
[segnum
-1].hSeg
);
485 TRACE_(module
)("(%d);\n", segnum
);
487 if (pSegTable
[segnum
-1].flags
& NE_SEGFLAGS_DATA
)
489 pSegTable
[segnum
-1].flags
|= NE_SEGFLAGS_LOADED
;
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
);
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
))
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
;
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 */
541 } while ( (bundle
->next
)
542 && (bundle
= ((ET_BUNDLE
*)((BYTE
*)pModule
+ bundle
->next
))) );
546 /***********************************************************************
549 * Needed for self-loading modules.
551 DWORD WINAPI
PatchCodeHandle16(HANDLE16 hSeg
)
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
);
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
)
587 ERR_(dll
)("Library is not marked SINGLEDATA\n");
590 else /* DATA NONE DLL */
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 ? */
611 *hInst
= *ds
? GlobalHandle16(*ds
) : pModule
->self
;
615 /***********************************************************************
618 * Call the DLL initialization code
620 static BOOL
NE_InitDLL( NE_MODULE
*pModule
)
622 SEGTABLEENTRY
*pSegTable
;
623 WORD hInst
, ds
, heap
;
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:
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
);
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 );
666 /***********************************************************************
669 * Recursively initialize all DLLs (according to the order in which
670 * they where loaded).
672 void NE_InitializeDLLs( HMODULE16 hModule
)
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 );
724 LPBYTE stack
= (LPBYTE
)CURRENT_STACK16
;
727 memset( &context
, 0, sizeof(context
) );
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
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
*) );
785 FIXME_(dll
)("Out of memory!");
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
)
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
)
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
)
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
++ )
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
)
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 /***********************************************************************
863 * This function translates NE segment flags to GlobalAlloc flags
865 static WORD
NE_Ne2MemFlags(WORD flags
)
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
;
880 memflags
= GMEM_ZEROINIT
| GMEM_FIXED
;
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
;
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
);
908 return MAKELONG( hMem
, SEL(hMem
) );
910 return MAKELONG( 0, hMem
);
913 /***********************************************************************
916 HINSTANCE16
NE_GetInstance( NE_MODULE
*pModule
)
918 if ( !pModule
->dgroup
)
919 return pModule
->self
;
923 pSeg
= NE_SEG_TABLE( pModule
) + pModule
->dgroup
- 1;
928 /***********************************************************************
931 BOOL
NE_CreateSegment( NE_MODULE
*pModule
, int segnum
)
933 SEGTABLEENTRY
*pSeg
= NE_SEG_TABLE( pModule
) + segnum
- 1;
935 unsigned char selflags
;
937 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
939 if ( segnum
< 1 || segnum
> pModule
->seg_count
)
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
;
961 /***********************************************************************
962 * NE_CreateAllSegments
964 BOOL
NE_CreateAllSegments( NE_MODULE
*pModule
)
967 for ( i
= 1; i
<= pModule
->seg_count
; i
++ )
968 if ( !NE_CreateSegment( pModule
, i
) )
971 pModule
->dgroup_entry
= pModule
->dgroup
? pModule
->seg_table
+
972 (pModule
->dgroup
- 1) * sizeof(SEGTABLEENTRY
) : 0;
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;