4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
11 #include <sys/types.h>
19 #include "wine/winbase16.h"
23 #include "selectors.h"
27 #include "stackframe.h"
28 #include "builtin16.h"
29 #include "debugtools.h"
32 DECLARE_DEBUG_CHANNEL(dll
)
33 DECLARE_DEBUG_CHANNEL(fixup
)
34 DECLARE_DEBUG_CHANNEL(module
)
35 DECLARE_DEBUG_CHANNEL(segment
)
37 #define SEL(x) ((x)|1)
39 static void NE_FixupSegmentPrologs(NE_MODULE
*pModule
, WORD segnum
);
41 /***********************************************************************
44 static const char *NE_GetRelocAddrName( BYTE addr_type
, int additive
)
46 switch(addr_type
& 0x7f)
48 case NE_RADDR_LOWBYTE
: return additive
? "BYTE add" : "BYTE";
49 case NE_RADDR_OFFSET16
: return additive
? "OFFSET16 add" : "OFFSET16";
50 case NE_RADDR_POINTER32
: return additive
? "POINTER32 add" : "POINTER32";
51 case NE_RADDR_SELECTOR
: return additive
? "SELECTOR add" : "SELECTOR";
52 case NE_RADDR_POINTER48
: return additive
? "POINTER48 add" : "POINTER48";
53 case NE_RADDR_OFFSET32
: return additive
? "OFFSET32 add" : "OFFSET32";
59 /***********************************************************************
62 BOOL
NE_LoadSegment( NE_MODULE
*pModule
, WORD segnum
)
64 SEGTABLEENTRY
*pSegTable
, *pSeg
;
66 WORD count
, i
, offset
, next_offset
;
68 FARPROC16 address
= 0;
71 struct relocation_entry_s
*rep
, *reloc_entries
;
77 int ordinal
, additive
;
80 pSegTable
= NE_SEG_TABLE( pModule
);
81 pSeg
= pSegTable
+ segnum
- 1;
83 if (pSeg
->flags
& NE_SEGFLAGS_LOADED
)
85 /* self-loader ? -> already loaded it */
86 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
89 /* leave, except for DGROUP, as this may be the second instance */
90 if (segnum
!= pModule
->dgroup
)
94 if (!pSeg
->filepos
) return TRUE
; /* No file image, just return */
96 pModuleTable
= NE_MODULE_TABLE( pModule
);
98 hf
= NE_OpenFile( pModule
);
99 TRACE_(module
)("Loading segment %d, hSeg=%04x, flags=%04x\n",
100 segnum
, pSeg
->hSeg
, pSeg
->flags
);
101 SetFilePointer( hf
, pSeg
->filepos
<< pModule
->alignment
, NULL
, SEEK_SET
);
102 if (pSeg
->size
) size
= pSeg
->size
;
103 else size
= pSeg
->minsize
? pSeg
->minsize
: 0x10000;
104 mem
= GlobalLock16(pSeg
->hSeg
);
105 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
&& segnum
> 1)
107 /* Implement self-loading segments */
108 SELFLOADHEADER
*selfloadheader
;
113 selfloadheader
= (SELFLOADHEADER
*)
114 PTR_SEG_OFF_TO_LIN(SEL(pSegTable
->hSeg
),0);
115 oldstack
= NtCurrentTeb()->cur_stack
;
116 NtCurrentTeb()->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
117 0xff00 - sizeof(STACK16FRAME
));
119 TRACE_(dll
)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
120 pModule
->self
,hf
,segnum
);
121 DuplicateHandle( GetCurrentProcess(), hf
, GetCurrentProcess(), &hFile32
,
122 0, FALSE
, DUPLICATE_SAME_ACCESS
);
123 hFile16
= FILE_AllocDosHandle( hFile32
);
124 pSeg
->hSeg
= Callbacks
->CallLoadAppSegProc( selfloadheader
->LoadAppSeg
,
125 pModule
->self
, hFile16
,
127 TRACE_(dll
)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg
->hSeg
);
128 _lclose16( hFile16
);
129 NtCurrentTeb()->cur_stack
= oldstack
;
131 else if (!(pSeg
->flags
& NE_SEGFLAGS_ITERATED
))
132 ReadFile(hf
, mem
, size
, &res
, NULL
);
135 The following bit of code for "iterated segments" was written without
136 any documentation on the format of these segments. It seems to work,
137 but may be missing something. If you have any doc please either send
138 it to me or fix the code yourself. gfm@werple.mira.net.au
140 char* buff
= HeapAlloc(GetProcessHeap(), 0, size
);
144 WARN_(dll
)("Memory exausted!");
148 ReadFile(hf
, buff
, size
, &res
, NULL
);
149 while(curr
< buff
+ size
) {
150 unsigned int rept
= *((short*) curr
)++;
151 unsigned int len
= *((short*) curr
)++;
152 for(; rept
> 0; rept
--) {
155 for(byte
= 0; byte
< len
; byte
++)
160 HeapFree(GetProcessHeap(), 0, buff
);
163 pSeg
->flags
|= NE_SEGFLAGS_LOADED
;
165 /* Perform exported function prolog fixups */
166 NE_FixupSegmentPrologs( pModule
, segnum
);
168 if (!(pSeg
->flags
& NE_SEGFLAGS_RELOC_DATA
))
169 return TRUE
; /* No relocation data, we are done */
171 ReadFile(hf
, &count
, sizeof(count
), &res
, NULL
);
172 if (!count
) return TRUE
;
174 TRACE_(fixup
)("Fixups for %.*s, segment %d, hSeg %04x\n",
175 *((BYTE
*)pModule
+ pModule
->name_table
),
176 (char *)pModule
+ pModule
->name_table
+ 1,
177 segnum
, pSeg
->hSeg
);
178 TRACE_(segment
)("Fixups for %.*s, segment %d, hSeg %04x\n",
179 *((BYTE
*)pModule
+ pModule
->name_table
),
180 (char *)pModule
+ pModule
->name_table
+ 1,
181 segnum
, pSeg
->hSeg
);
183 reloc_entries
= (struct relocation_entry_s
*)HeapAlloc(GetProcessHeap(), 0, count
* sizeof(struct relocation_entry_s
));
184 if(reloc_entries
== NULL
) {
185 WARN_(fixup
)("Not enough memory for relocation entries!");
188 if (!ReadFile( hf
, reloc_entries
, count
* sizeof(struct relocation_entry_s
), &res
, NULL
) ||
189 (res
!= count
* sizeof(struct relocation_entry_s
)))
191 WARN_(fixup
)("Unable to read relocation information\n" );
196 * Go through the relocation table one entry at a time.
199 for (i
= 0; i
< count
; i
++, rep
++)
202 * Get the target address corresponding to this entry.
205 /* If additive, there is no target chain list. Instead, add source
207 additive
= rep
->relocation_type
& NE_RELFLAG_ADDITIVE
;
208 rep
->relocation_type
&= 0x3;
210 switch (rep
->relocation_type
)
212 case NE_RELTYPE_ORDINAL
:
213 module
= pModuleTable
[rep
->target1
-1];
214 ordinal
= rep
->target2
;
215 address
= NE_GetEntryPoint( module
, ordinal
);
218 NE_MODULE
*pTarget
= NE_GetPtr( module
);
220 WARN_(module
)("Module not found: %04x, reference %d of module %*.*s\n",
221 module
, rep
->target1
,
222 *((BYTE
*)pModule
+ pModule
->name_table
),
223 *((BYTE
*)pModule
+ pModule
->name_table
),
224 (char *)pModule
+ pModule
->name_table
+ 1 );
227 ERR_(fixup
)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
228 *((BYTE
*)pTarget
+ pTarget
->name_table
),
229 (char *)pTarget
+ pTarget
->name_table
+ 1,
231 address
= (FARPROC16
)0xdeadbeef;
236 NE_MODULE
*pTarget
= NE_GetPtr( module
);
237 TRACE_(fixup
)("%d: %.*s.%d=%04x:%04x %s\n", i
+ 1,
238 *((BYTE
*)pTarget
+ pTarget
->name_table
),
239 (char *)pTarget
+ pTarget
->name_table
+ 1,
240 ordinal
, HIWORD(address
), LOWORD(address
),
241 NE_GetRelocAddrName( rep
->address_type
, additive
) );
245 case NE_RELTYPE_NAME
:
246 module
= pModuleTable
[rep
->target1
-1];
247 func_name
= (char *)pModule
+ pModule
->import_table
+ rep
->target2
;
248 memcpy( buffer
, func_name
+1, *func_name
);
249 buffer
[*func_name
] = '\0';
251 ordinal
= NE_GetOrdinal( module
, func_name
);
252 address
= NE_GetEntryPoint( module
, ordinal
);
254 if (ERR_ON(fixup
) && !address
)
256 NE_MODULE
*pTarget
= NE_GetPtr( module
);
257 ERR_(fixup
)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
258 *((BYTE
*)pTarget
+ pTarget
->name_table
),
259 (char *)pTarget
+ pTarget
->name_table
+ 1, func_name
);
261 if (!address
) address
= (FARPROC16
) 0xdeadbeef;
264 NE_MODULE
*pTarget
= NE_GetPtr( module
);
265 TRACE_(fixup
)("%d: %.*s.%s=%04x:%04x %s\n", i
+ 1,
266 *((BYTE
*)pTarget
+ pTarget
->name_table
),
267 (char *)pTarget
+ pTarget
->name_table
+ 1,
268 func_name
, HIWORD(address
), LOWORD(address
),
269 NE_GetRelocAddrName( rep
->address_type
, additive
) );
273 case NE_RELTYPE_INTERNAL
:
274 if ((rep
->target1
& 0xff) == 0xff)
276 address
= NE_GetEntryPoint( pModule
->self
, rep
->target2
);
280 address
= (FARPROC16
)PTR_SEG_OFF_TO_SEGPTR( SEL(pSegTable
[rep
->target1
-1].hSeg
), rep
->target2
);
283 TRACE_(fixup
)("%d: %04x:%04x %s\n",
284 i
+ 1, HIWORD(address
), LOWORD(address
),
285 NE_GetRelocAddrName( rep
->address_type
, additive
) );
288 case NE_RELTYPE_OSFIXUP
:
289 /* Relocation type 7:
291 * These appear to be used as fixups for the Windows
292 * floating point emulator. Let's just ignore them and
293 * try to use the hardware floating point. Linux should
294 * successfully emulate the coprocessor if it doesn't
297 TRACE_(fixup
)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
298 i
+ 1, rep
->relocation_type
, rep
->offset
,
299 rep
->target1
, rep
->target2
,
300 NE_GetRelocAddrName( rep
->address_type
, additive
) );
304 offset
= rep
->offset
;
306 /* Apparently, high bit of address_type is sometimes set; */
307 /* we ignore it for now */
308 if (rep
->address_type
> NE_RADDR_OFFSET32
)
311 GetModuleName16( pModule
->self
, module
, sizeof(module
) );
312 ERR_(fixup
)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
313 module
, rep
->address_type
);
318 sp
= PTR_SEG_OFF_TO_LIN( SEL(pSeg
->hSeg
), offset
);
319 TRACE_(fixup
)(" %04x:%04x\n", offset
, *sp
);
320 switch (rep
->address_type
& 0x7f)
322 case NE_RADDR_LOWBYTE
:
323 *(BYTE
*)sp
+= LOBYTE((int)address
);
325 case NE_RADDR_OFFSET16
:
326 *sp
+= LOWORD(address
);
328 case NE_RADDR_POINTER32
:
329 *sp
+= LOWORD(address
);
330 *(sp
+1) = HIWORD(address
);
332 case NE_RADDR_SELECTOR
:
333 /* Borland creates additive records with offset zero. Strange, but OK */
335 ERR_(fixup
)("Additive selector to %04x.Please report\n",*sp
);
337 *sp
= HIWORD(address
);
343 else /* non-additive fixup */
347 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
);
355 case NE_RADDR_OFFSET16
:
356 *sp
= LOWORD(address
);
358 case NE_RADDR_POINTER32
:
359 *(FARPROC16
*)sp
= address
;
361 case NE_RADDR_SELECTOR
:
362 *sp
= SELECTOROF(address
);
367 if (next_offset
== offset
) break; /* avoid infinite loop */
368 if (next_offset
>= GlobalSize16(pSeg
->hSeg
)) break;
369 offset
= next_offset
;
370 } while (offset
!= 0xffff);
374 HeapFree(GetProcessHeap(), 0, reloc_entries
);
378 WARN_(fixup
)("WARNING: %d: unknown ADDR TYPE %d, "
379 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
380 i
+ 1, rep
->address_type
, rep
->relocation_type
,
381 rep
->offset
, rep
->target1
, rep
->target2
);
382 HeapFree(GetProcessHeap(), 0, reloc_entries
);
387 /***********************************************************************
390 BOOL
NE_LoadAllSegments( NE_MODULE
*pModule
)
393 SEGTABLEENTRY
* pSegTable
= (SEGTABLEENTRY
*) NE_SEG_TABLE(pModule
);
395 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
399 /* Handle self-loading modules */
400 SELFLOADHEADER
*selfloadheader
;
401 HMODULE16 hselfload
= GetModuleHandle16("WPROCS");
404 TRACE_(module
)("%.*s is a self-loading module!\n",
405 *((BYTE
*)pModule
+ pModule
->name_table
),
406 (char *)pModule
+ pModule
->name_table
+ 1);
407 if (!NE_LoadSegment( pModule
, 1 )) return FALSE
;
408 selfloadheader
= (SELFLOADHEADER
*)
409 PTR_SEG_OFF_TO_LIN(SEL(pSegTable
->hSeg
), 0);
410 selfloadheader
->EntryAddrProc
= NE_GetEntryPoint(hselfload
,27);
411 selfloadheader
->MyAlloc
= NE_GetEntryPoint(hselfload
,28);
412 selfloadheader
->SetOwner
= NE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
413 pModule
->self_loading_sel
= SEL(GLOBAL_Alloc(GMEM_ZEROINIT
, 0xFF00, pModule
->self
, FALSE
, FALSE
, FALSE
));
414 oldstack
= NtCurrentTeb()->cur_stack
;
415 NtCurrentTeb()->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
416 0xff00 - sizeof(STACK16FRAME
) );
418 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule
),
419 GetCurrentProcess(), &hf
, 0, FALSE
, DUPLICATE_SAME_ACCESS
);
420 hFile16
= FILE_AllocDosHandle( hf
);
421 TRACE_(dll
)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
422 pModule
->self
,hFile16
);
423 Callbacks
->CallBootAppProc(selfloadheader
->BootApp
, pModule
->self
,hFile16
);
424 TRACE_(dll
)("Return from CallBootAppProc\n");
426 NtCurrentTeb()->cur_stack
= oldstack
;
428 for (i
= 2; i
<= pModule
->seg_count
; i
++)
429 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
433 for (i
= 1; i
<= pModule
->seg_count
; i
++)
434 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
440 /***********************************************************************
441 * NE_FixupSegmentPrologs
443 * Fixup exported functions prologs of one segment
445 static void NE_FixupSegmentPrologs(NE_MODULE
*pModule
, WORD segnum
)
447 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE( pModule
);
450 WORD dgroup
, num_entries
, sel
= SEL(pSegTable
[segnum
-1].hSeg
);
453 TRACE_(module
)("(%d);\n", segnum
);
455 if (pSegTable
[segnum
-1].flags
& NE_SEGFLAGS_DATA
)
457 pSegTable
[segnum
-1].flags
|= NE_SEGFLAGS_LOADED
;
461 if (!pModule
->dgroup
) return;
463 if (!(dgroup
= SEL(pSegTable
[pModule
->dgroup
-1].hSeg
))) return;
465 pSeg
= PTR_SEG_OFF_TO_LIN(sel
, 0);
467 bundle
= (ET_BUNDLE
*)((BYTE
*)pModule
+pModule
->entry_table
);
470 TRACE_(module
)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle
->last
- bundle
->first
, bundle
, bundle
->next
, pSeg
);
471 if (!(num_entries
= bundle
->last
- bundle
->first
))
473 entry
= (ET_ENTRY
*)((BYTE
*)bundle
+6);
474 while (num_entries
--)
476 /*TRACE(module, "entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
477 if (entry
->segnum
== segnum
)
479 pFunc
= ((BYTE
*)pSeg
+entry
->offs
);
480 TRACE_(module
)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc
, *(DWORD
*)pFunc
, num_entries
);
481 if (*(pFunc
+2) == 0x90)
483 if (*(WORD
*)pFunc
== 0x581e) /* push ds, pop ax */
485 TRACE_(module
)("patch %04x:%04x -> mov ax, ds\n", sel
, entry
->offs
);
486 *(WORD
*)pFunc
= 0xd88c; /* mov ax, ds */
489 if (*(WORD
*)pFunc
== 0xd88c)
491 if ((entry
->flags
& 2)) /* public data ? */
493 TRACE_(module
)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel
, entry
->offs
, dgroup
);
494 *pFunc
= 0xb8; /* mov ax, */
495 *(WORD
*)(pFunc
+1) = dgroup
;
498 if ((pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
)
499 && (entry
->flags
& 1)) /* exported ? */
501 TRACE_(module
)("patch %04x:%04x -> nop, nop\n", sel
, entry
->offs
);
502 *(WORD
*)pFunc
= 0x9090; /* nop, nop */
509 } while ( (bundle
->next
)
510 && (bundle
= ((ET_BUNDLE
*)((BYTE
*)pModule
+ bundle
->next
))) );
514 /***********************************************************************
517 * Needed for self-loading modules.
519 DWORD WINAPI
PatchCodeHandle16(HANDLE16 hSeg
)
522 WORD sel
= SEL(hSeg
);
523 NE_MODULE
*pModule
= NE_GetPtr(FarGetOwner16(sel
));
524 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE(pModule
);
526 TRACE_(module
)("(%04x);\n", hSeg
);
528 /* find the segment number of the module that belongs to hSeg */
529 for (segnum
= 1; segnum
<= pModule
->seg_count
; segnum
++)
531 if (SEL(pSegTable
[segnum
-1].hSeg
) == sel
)
533 NE_FixupSegmentPrologs(pModule
, segnum
);
538 return MAKELONG(hSeg
, sel
);
542 /***********************************************************************
543 * NE_GetDLLInitParams
545 static VOID
NE_GetDLLInitParams( NE_MODULE
*pModule
,
546 WORD
*hInst
, WORD
*ds
, WORD
*heap
)
548 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE( pModule
);
550 if (!(pModule
->flags
& NE_FFLAGS_SINGLEDATA
))
552 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
|| pModule
->dgroup
)
555 ERR_(dll
)("Library is not marked SINGLEDATA\n");
558 else /* DATA NONE DLL */
564 else /* DATA SINGLE DLL */
566 if (pModule
->dgroup
) {
567 *ds
= SEL(pSegTable
[pModule
->dgroup
-1].hSeg
);
568 *heap
= pModule
->heap_size
;
570 else /* hmm, DLL has no dgroup,
571 but why has it NE_FFLAGS_SINGLEDATA set ?
572 Buggy DLL compiler ? */
579 *hInst
= *ds
? GlobalHandle16(*ds
) : pModule
->self
;
583 /***********************************************************************
586 * Call the DLL initialization code
588 static BOOL
NE_InitDLL( TDB
* pTask
, NE_MODULE
*pModule
)
590 SEGTABLEENTRY
*pSegTable
;
591 WORD hInst
, ds
, heap
;
594 pSegTable
= NE_SEG_TABLE( pModule
);
596 if (!(pModule
->flags
& NE_FFLAGS_LIBMODULE
) ||
597 (pModule
->flags
& NE_FFLAGS_WIN32
)) return TRUE
; /*not a library*/
599 /* Call USER signal handler for Win3.1 compatibility. */
600 TASK_CallTaskSignalProc( USIG16_DLL_LOAD
, pModule
->self
);
602 if (!pModule
->cs
) return TRUE
; /* no initialization code */
605 /* Registers at initialization must be:
607 * di library instance
608 * ds data segment if any
609 * es:si command line (always 0)
612 memset( &context
, 0, sizeof(context
) );
614 NE_GetDLLInitParams( pModule
, &hInst
, &ds
, &heap
);
616 ECX_reg(&context
) = heap
;
617 EDI_reg(&context
) = hInst
;
618 DS_reg(&context
) = ds
;
619 ES_reg(&context
) = ds
; /* who knows ... */
621 CS_reg(&context
) = SEL(pSegTable
[pModule
->cs
-1].hSeg
);
622 EIP_reg(&context
) = pModule
->ip
;
623 EBP_reg(&context
) = OFFSETOF(NtCurrentTeb()->cur_stack
) + (WORD
)&((STACK16FRAME
*)0)->bp
;
626 pModule
->cs
= 0; /* Don't initialize it twice */
627 TRACE_(dll
)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
628 CS_reg(&context
), EIP_reg(&context
), DS_reg(&context
),
629 DI_reg(&context
), CX_reg(&context
) );
630 Callbacks
->CallRegisterShortProc( &context
, 0 );
634 /***********************************************************************
637 * Recursively initialize all DLLs (according to the order in which
638 * they where loaded).
640 void NE_InitializeDLLs( HMODULE16 hModule
)
642 TDB
* pTask
= (TDB
*)GlobalLock16(GetCurrentTask());
646 if (!(pModule
= NE_GetPtr( hModule
))) return;
647 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
649 if (pModule
->dlls_to_init
)
651 HGLOBAL16 to_init
= pModule
->dlls_to_init
;
652 pModule
->dlls_to_init
= 0;
653 for (pDLL
= (HMODULE16
*)GlobalLock16( to_init
); *pDLL
; pDLL
++)
655 NE_InitializeDLLs( *pDLL
);
657 GlobalFree16( to_init
);
659 NE_InitDLL( pTask
, pModule
);
663 /***********************************************************************
664 * NE_CallDllEntryPoint
666 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
668 typedef DWORD
WINAPI (*WinNEEntryProc
)(DWORD
,WORD
,WORD
,WORD
,DWORD
,WORD
);
670 static void NE_CallDllEntryPoint( NE_MODULE
*pModule
, DWORD dwReason
)
672 WORD hInst
, ds
, heap
;
673 FARPROC16 entryPoint
;
676 if (!(pModule
->flags
& NE_FFLAGS_LIBMODULE
)) return;
677 if (!(pModule
->flags
& NE_FFLAGS_BUILTIN
) && pModule
->expected_version
< 0x0400) return;
678 if (!(ordinal
= NE_GetOrdinal( pModule
->self
, "DllEntryPoint" ))) return;
679 if (!(entryPoint
= NE_GetEntryPoint( pModule
->self
, ordinal
))) return;
681 NE_GetDLLInitParams( pModule
, &hInst
, &ds
, &heap
);
683 TRACE_(dll
)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
684 NE_MODULE_NAME( pModule
),
685 SELECTOROF(entryPoint
), OFFSETOF(entryPoint
) );
687 if ( pModule
->flags
& NE_FFLAGS_BUILTIN
)
689 WinNEEntryProc entryProc
= (WinNEEntryProc
)
690 ((ENTRYPOINT16
*)PTR_SEG_TO_LIN( entryPoint
))->target
;
692 entryProc( dwReason
, hInst
, ds
, heap
, 0, 0 );
696 LPBYTE stack
= (LPBYTE
)CURRENT_STACK16
;
699 memset( &context
, 0, sizeof(context
) );
700 DS_reg(&context
) = ds
;
701 ES_reg(&context
) = ds
; /* who knows ... */
703 CS_reg(&context
) = HIWORD(entryPoint
);
704 EIP_reg(&context
) = LOWORD(entryPoint
);
705 EBP_reg(&context
) = OFFSETOF( NtCurrentTeb()->cur_stack
)
706 + (WORD
)&((STACK16FRAME
*)0)->bp
;
708 *(DWORD
*)(stack
- 4) = dwReason
; /* dwReason */
709 *(WORD
*) (stack
- 6) = hInst
; /* hInst */
710 *(WORD
*) (stack
- 8) = ds
; /* wDS */
711 *(WORD
*) (stack
- 10) = heap
; /* wHeapSize */
712 *(DWORD
*)(stack
- 14) = 0; /* dwReserved1 */
713 *(WORD
*) (stack
- 16) = 0; /* wReserved2 */
715 Callbacks
->CallRegisterShortProc( &context
, 16 );
719 /***********************************************************************
720 * NE_DllProcessAttach
722 * Call the DllEntryPoint of all modules this one (recursively)
723 * depends on, according to the order in which they were loaded.
725 * Note that --as opposed to the PE module case-- there is no notion
726 * of 'module loaded into a process' for NE modules, and hence we
727 * have no place to store the fact that the DllEntryPoint of a
728 * given module was already called on behalf of this process (e.g.
729 * due to some earlier LoadLibrary16 call).
731 * Thus, we just call the DllEntryPoint twice in that case. Win9x
732 * appears to behave this way as well ...
734 * This routine must only be called with the Win16Lock held.
736 * FIXME: We should actually abort loading in case the DllEntryPoint
740 void NE_DllProcessAttach( HMODULE16 hModule
)
746 if (!(pModule
= NE_GetPtr( hModule
))) return;
747 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
749 /* Check for recursive call */
750 if ( pModule
->misc_flags
& 0x80 ) return;
752 TRACE_(dll
)("(%s) - START\n", NE_MODULE_NAME(pModule
) );
754 /* Tag current module to prevent recursive loop */
755 pModule
->misc_flags
|= 0x80;
757 /* Recursively attach all DLLs this one depends on */
758 pModRef
= NE_MODULE_TABLE( pModule
);
759 for ( i
= 0; i
< pModule
->modref_count
; i
++ )
761 NE_DllProcessAttach( (HMODULE16
)pModRef
[i
] );
763 /* Call DLL entry point */
764 NE_CallDllEntryPoint( pModule
, DLL_PROCESS_ATTACH
);
766 /* Remove recursion flag */
767 pModule
->misc_flags
&= ~0x80;
769 TRACE_(dll
)("(%s) - END\n", NE_MODULE_NAME(pModule
) );
773 /***********************************************************************
776 * This function translates NE segment flags to GlobalAlloc flags
778 static WORD
NE_Ne2MemFlags(WORD flags
)
782 if (flags
& NE_SEGFLAGS_DISCARDABLE
)
783 memflags
|= GMEM_DISCARDABLE
;
784 if (flags
& NE_SEGFLAGS_MOVEABLE
||
785 ( ! (flags
& NE_SEGFLAGS_DATA
) &&
786 ! (flags
& NE_SEGFLAGS_LOADED
) &&
787 ! (flags
& NE_SEGFLAGS_ALLOCATED
)
790 memflags
|= GMEM_MOVEABLE
;
791 memflags
|= GMEM_ZEROINIT
;
793 memflags
= GMEM_ZEROINIT
| GMEM_FIXED
;
798 /***********************************************************************
799 * NE_AllocateSegment (WPROCS.26)
801 * MyAlloc() function for self-loading apps.
803 DWORD WINAPI
NE_AllocateSegment( WORD wFlags
, WORD wSize
, WORD wElem
)
805 WORD size
= wSize
<< wElem
;
808 if (wSize
|| (wFlags
& NE_SEGFLAGS_MOVEABLE
))
809 hMem
= GlobalAlloc16( NE_Ne2MemFlags(wFlags
), size
);
811 if ( ((wFlags
& 0x7) != 0x1) && /* DATA */
812 ((wFlags
& 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
814 WORD hSel
= SEL(hMem
);
815 WORD access
= SelectorAccessRights16(hSel
,0,0);
817 access
|= 2<<2; /* SEGMENT_CODE */
818 SelectorAccessRights16(hSel
,1,access
);
821 return MAKELONG( hMem
, SEL(hMem
) );
823 return MAKELONG( 0, hMem
);
826 /***********************************************************************
829 HINSTANCE16
NE_GetInstance( NE_MODULE
*pModule
)
831 if ( !pModule
->dgroup
)
832 return pModule
->self
;
836 pSeg
= NE_SEG_TABLE( pModule
) + pModule
->dgroup
- 1;
841 /***********************************************************************
844 BOOL
NE_CreateSegment( NE_MODULE
*pModule
, int segnum
)
846 SEGTABLEENTRY
*pSeg
= NE_SEG_TABLE( pModule
) + segnum
- 1;
849 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
851 if ( segnum
< 1 || segnum
> pModule
->seg_count
)
854 if ( (pModule
->flags
& NE_FFLAGS_SELFLOAD
) && segnum
!= 1 )
855 return TRUE
; /* selfloader allocates segment itself */
857 if ( (pSeg
->flags
& NE_SEGFLAGS_ALLOCATED
) && segnum
!= pModule
->dgroup
)
858 return TRUE
; /* all but DGROUP only allocated once */
860 minsize
= pSeg
->minsize
? pSeg
->minsize
: 0x10000;
861 if ( segnum
== pModule
->ss
) minsize
+= pModule
->stack_size
;
862 if ( segnum
== pModule
->dgroup
) minsize
+= pModule
->heap_size
;
864 pSeg
->hSeg
= GLOBAL_Alloc( NE_Ne2MemFlags(pSeg
->flags
),
865 minsize
, pModule
->self
,
866 !(pSeg
->flags
& NE_SEGFLAGS_DATA
),
867 (pSeg
->flags
& NE_SEGFLAGS_32BIT
) != 0,
868 FALSE
/*pSeg->flags & NE_SEGFLAGS_READONLY*/ );
869 if (!pSeg
->hSeg
) return FALSE
;
871 pSeg
->flags
|= NE_SEGFLAGS_ALLOCATED
;
875 /***********************************************************************
876 * NE_CreateAllSegments
878 BOOL
NE_CreateAllSegments( NE_MODULE
*pModule
)
881 for ( i
= 1; i
<= pModule
->seg_count
; i
++ )
882 if ( !NE_CreateSegment( pModule
, i
) )
885 pModule
->dgroup_entry
= pModule
->dgroup
? pModule
->seg_table
+
886 (pModule
->dgroup
- 1) * sizeof(SEGTABLEENTRY
) : 0;
891 /**********************************************************************
892 * IsSharedSelector (KERNEL.345)
894 BOOL16 WINAPI
IsSharedSelector16( HANDLE16 selector
)
896 /* Check whether the selector belongs to a DLL */
897 NE_MODULE
*pModule
= NE_GetPtr( selector
);
898 if (!pModule
) return FALSE
;
899 return (pModule
->flags
& NE_FFLAGS_LIBMODULE
) != 0;