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 "debugtools.h"
31 DECLARE_DEBUG_CHANNEL(dll
)
32 DECLARE_DEBUG_CHANNEL(fixup
)
33 DECLARE_DEBUG_CHANNEL(module
)
34 DECLARE_DEBUG_CHANNEL(segment
)
36 #define SEL(x) GlobalHandleToSel16(x)
38 /***********************************************************************
41 static const char *NE_GetRelocAddrName( BYTE addr_type
, int additive
)
43 switch(addr_type
& 0x7f)
45 case NE_RADDR_LOWBYTE
: return additive
? "BYTE add" : "BYTE";
46 case NE_RADDR_OFFSET16
: return additive
? "OFFSET16 add" : "OFFSET16";
47 case NE_RADDR_POINTER32
: return additive
? "POINTER32 add" : "POINTER32";
48 case NE_RADDR_SELECTOR
: return additive
? "SELECTOR add" : "SELECTOR";
49 case NE_RADDR_POINTER48
: return additive
? "POINTER48 add" : "POINTER48";
50 case NE_RADDR_OFFSET32
: return additive
? "OFFSET32 add" : "OFFSET32";
56 /***********************************************************************
59 BOOL
NE_LoadSegment( NE_MODULE
*pModule
, WORD segnum
)
61 SEGTABLEENTRY
*pSegTable
, *pSeg
;
63 WORD count
, i
, offset
, next_offset
;
65 FARPROC16 address
= 0;
68 struct relocation_entry_s
*rep
, *reloc_entries
;
74 int ordinal
, additive
;
77 pSegTable
= NE_SEG_TABLE( pModule
);
78 pSeg
= pSegTable
+ segnum
- 1;
80 if (pSeg
->flags
& NE_SEGFLAGS_LOADED
) /* already loaded ? */
83 if (!pSeg
->filepos
) return TRUE
; /* No file image, just return */
85 pModuleTable
= NE_MODULE_TABLE( pModule
);
87 hf
= NE_OpenFile( pModule
);
88 TRACE_(module
)("Loading segment %d, hSeg=%04x, flags=%04x\n",
89 segnum
, pSeg
->hSeg
, pSeg
->flags
);
90 SetFilePointer( hf
, pSeg
->filepos
<< pModule
->alignment
, NULL
, SEEK_SET
);
91 if (pSeg
->size
) size
= pSeg
->size
;
92 else size
= pSeg
->minsize
? pSeg
->minsize
: 0x10000;
93 mem
= GlobalLock16(pSeg
->hSeg
);
94 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
&& segnum
> 1)
96 /* Implement self-loading segments */
97 SELFLOADHEADER
*selfloadheader
;
98 STACK16FRAME
*stack16Top
;
100 WORD old_hSeg
, new_hSeg
;
101 THDB
*thdb
= THREAD_Current();
105 selfloadheader
= (SELFLOADHEADER
*)
106 PTR_SEG_OFF_TO_LIN(SEL(pSegTable
->hSeg
),0);
107 oldstack
= thdb
->cur_stack
;
108 old_hSeg
= pSeg
->hSeg
;
109 thdb
->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
110 0xff00 - sizeof(*stack16Top
));
111 stack16Top
= (STACK16FRAME
*)PTR_SEG_TO_LIN(thdb
->cur_stack
);
112 stack16Top
->frame32
= 0;
113 stack16Top
->ds
= stack16Top
->es
= pModule
->self_loading_sel
;
114 stack16Top
->entry_point
= 0;
115 stack16Top
->entry_ip
= 0;
116 stack16Top
->entry_cs
= 0;
120 TRACE_(dll
)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
121 pModule
->self
,hf
,segnum
);
122 DuplicateHandle( GetCurrentProcess(), hf
, GetCurrentProcess(), &hFile32
,
123 0, FALSE
, DUPLICATE_SAME_ACCESS
);
124 hFile16
= FILE_AllocDosHandle( hFile32
);
125 new_hSeg
= Callbacks
->CallLoadAppSegProc(selfloadheader
->LoadAppSeg
,
126 pModule
->self
, hFile16
,
128 TRACE_(dll
)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n",new_hSeg
);
129 _lclose16( hFile16
);
130 if (SEL(new_hSeg
) != SEL(old_hSeg
)) {
131 /* Self loaders like creating their own selectors;
132 * they love asking for trouble to Wine developers
134 if (segnum
== pModule
->dgroup
) {
135 memcpy(PTR_SEG_OFF_TO_LIN(SEL(old_hSeg
),0),
136 PTR_SEG_OFF_TO_LIN(SEL(new_hSeg
),0),
137 pSeg
->minsize
? pSeg
->minsize
: 0x10000);
138 FreeSelector16(SEL(new_hSeg
));
139 pSeg
->hSeg
= old_hSeg
;
140 TRACE_(module
)("New hSeg allocated for dgroup segment:Old=%d,New=%d\n",
143 FreeSelector16(SEL(pSeg
->hSeg
));
144 pSeg
->hSeg
= new_hSeg
;
148 thdb
->cur_stack
= oldstack
;
150 else if (!(pSeg
->flags
& NE_SEGFLAGS_ITERATED
))
151 ReadFile(hf
, mem
, size
, &res
, NULL
);
154 The following bit of code for "iterated segments" was written without
155 any documentation on the format of these segments. It seems to work,
156 but may be missing something. If you have any doc please either send
157 it to me or fix the code yourself. gfm@werple.mira.net.au
159 char* buff
= xmalloc(size
);
161 ReadFile(hf
, buff
, size
, &res
, NULL
);
162 while(curr
< buff
+ size
) {
163 unsigned int rept
= *((short*) curr
)++;
164 unsigned int len
= *((short*) curr
)++;
165 for(; rept
> 0; rept
--) {
168 for(byte
= 0; byte
< len
; byte
++)
176 pSeg
->flags
|= NE_SEGFLAGS_LOADED
;
177 if (!(pSeg
->flags
& NE_SEGFLAGS_RELOC_DATA
))
178 return TRUE
; /* No relocation data, we are done */
180 ReadFile(hf
, &count
, sizeof(count
), &res
, NULL
);
181 if (!count
) return TRUE
;
183 TRACE_(fixup
)("Fixups for %.*s, segment %d, hSeg %04x\n",
184 *((BYTE
*)pModule
+ pModule
->name_table
),
185 (char *)pModule
+ pModule
->name_table
+ 1,
186 segnum
, pSeg
->hSeg
);
187 TRACE_(segment
)("Fixups for %.*s, segment %d, hSeg %04x\n",
188 *((BYTE
*)pModule
+ pModule
->name_table
),
189 (char *)pModule
+ pModule
->name_table
+ 1,
190 segnum
, pSeg
->hSeg
);
192 reloc_entries
= (struct relocation_entry_s
*)xmalloc(count
* sizeof(struct relocation_entry_s
));
193 if (!ReadFile( hf
, reloc_entries
, count
* sizeof(struct relocation_entry_s
), &res
, NULL
) ||
194 (res
!= count
* sizeof(struct relocation_entry_s
)))
196 WARN_(fixup
)("Unable to read relocation information\n" );
201 * Go through the relocation table one entry at a time.
204 for (i
= 0; i
< count
; i
++, rep
++)
207 * Get the target address corresponding to this entry.
210 /* If additive, there is no target chain list. Instead, add source
212 additive
= rep
->relocation_type
& NE_RELFLAG_ADDITIVE
;
213 rep
->relocation_type
&= 0x3;
215 switch (rep
->relocation_type
)
217 case NE_RELTYPE_ORDINAL
:
218 module
= pModuleTable
[rep
->target1
-1];
219 ordinal
= rep
->target2
;
220 address
= NE_GetEntryPoint( module
, ordinal
);
223 NE_MODULE
*pTarget
= NE_GetPtr( module
);
225 WARN_(module
)("Module not found: %04x, reference %d of module %*.*s\n",
226 module
, rep
->target1
,
227 *((BYTE
*)pModule
+ pModule
->name_table
),
228 *((BYTE
*)pModule
+ pModule
->name_table
),
229 (char *)pModule
+ pModule
->name_table
+ 1 );
232 ERR_(fixup
)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
233 *((BYTE
*)pTarget
+ pTarget
->name_table
),
234 (char *)pTarget
+ pTarget
->name_table
+ 1,
236 address
= (FARPROC16
)0xdeadbeef;
241 NE_MODULE
*pTarget
= NE_GetPtr( module
);
242 TRACE_(fixup
)("%d: %.*s.%d=%04x:%04x %s\n", i
+ 1,
243 *((BYTE
*)pTarget
+ pTarget
->name_table
),
244 (char *)pTarget
+ pTarget
->name_table
+ 1,
245 ordinal
, HIWORD(address
), LOWORD(address
),
246 NE_GetRelocAddrName( rep
->address_type
, additive
) );
250 case NE_RELTYPE_NAME
:
251 module
= pModuleTable
[rep
->target1
-1];
252 func_name
= (char *)pModule
+ pModule
->import_table
+ rep
->target2
;
253 memcpy( buffer
, func_name
+1, *func_name
);
254 buffer
[*func_name
] = '\0';
256 ordinal
= NE_GetOrdinal( module
, func_name
);
257 address
= NE_GetEntryPoint( module
, ordinal
);
259 if (ERR_ON(fixup
) && !address
)
261 NE_MODULE
*pTarget
= NE_GetPtr( module
);
262 ERR_(fixup
)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
263 *((BYTE
*)pTarget
+ pTarget
->name_table
),
264 (char *)pTarget
+ pTarget
->name_table
+ 1, func_name
);
266 if (!address
) address
= (FARPROC16
) 0xdeadbeef;
269 NE_MODULE
*pTarget
= NE_GetPtr( module
);
270 TRACE_(fixup
)("%d: %.*s.%s=%04x:%04x %s\n", i
+ 1,
271 *((BYTE
*)pTarget
+ pTarget
->name_table
),
272 (char *)pTarget
+ pTarget
->name_table
+ 1,
273 func_name
, HIWORD(address
), LOWORD(address
),
274 NE_GetRelocAddrName( rep
->address_type
, additive
) );
278 case NE_RELTYPE_INTERNAL
:
279 if ((rep
->target1
& 0xff) == 0xff)
281 address
= NE_GetEntryPoint( pModule
->self
, rep
->target2
);
285 address
= (FARPROC16
)PTR_SEG_OFF_TO_SEGPTR( SEL(pSegTable
[rep
->target1
-1].hSeg
), rep
->target2
);
288 TRACE_(fixup
)("%d: %04x:%04x %s\n",
289 i
+ 1, HIWORD(address
), LOWORD(address
),
290 NE_GetRelocAddrName( rep
->address_type
, additive
) );
293 case NE_RELTYPE_OSFIXUP
:
294 /* Relocation type 7:
296 * These appear to be used as fixups for the Windows
297 * floating point emulator. Let's just ignore them and
298 * try to use the hardware floating point. Linux should
299 * successfully emulate the coprocessor if it doesn't
302 TRACE_(fixup
)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
303 i
+ 1, rep
->relocation_type
, rep
->offset
,
304 rep
->target1
, rep
->target2
,
305 NE_GetRelocAddrName( rep
->address_type
, additive
) );
309 offset
= rep
->offset
;
311 /* Apparently, high bit of address_type is sometimes set; */
312 /* we ignore it for now */
313 if (rep
->address_type
> NE_RADDR_OFFSET32
)
316 GetModuleName16( pModule
->self
, module
, sizeof(module
) );
317 ERR_(fixup
)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
318 module
, rep
->address_type
);
323 sp
= PTR_SEG_OFF_TO_LIN( SEL(pSeg
->hSeg
), offset
);
324 TRACE_(fixup
)(" %04x:%04x\n", offset
, *sp
);
325 switch (rep
->address_type
& 0x7f)
327 case NE_RADDR_LOWBYTE
:
328 *(BYTE
*)sp
+= LOBYTE((int)address
);
330 case NE_RADDR_OFFSET16
:
331 *sp
+= LOWORD(address
);
333 case NE_RADDR_POINTER32
:
334 *sp
+= LOWORD(address
);
335 *(sp
+1) = HIWORD(address
);
337 case NE_RADDR_SELECTOR
:
338 /* Borland creates additive records with offset zero. Strange, but OK */
340 ERR_(fixup
)("Additive selector to %04x.Please report\n",*sp
);
342 *sp
= HIWORD(address
);
348 else /* non-additive fixup */
352 sp
= PTR_SEG_OFF_TO_LIN( SEL(pSeg
->hSeg
), offset
);
354 TRACE_(fixup
)(" %04x:%04x\n", offset
, *sp
);
355 switch (rep
->address_type
& 0x7f)
357 case NE_RADDR_LOWBYTE
:
358 *(BYTE
*)sp
= LOBYTE((int)address
);
360 case NE_RADDR_OFFSET16
:
361 *sp
= LOWORD(address
);
363 case NE_RADDR_POINTER32
:
364 *(FARPROC16
*)sp
= address
;
366 case NE_RADDR_SELECTOR
:
367 *sp
= SELECTOROF(address
);
372 if (next_offset
== offset
) break; /* avoid infinite loop */
373 if (next_offset
>= GlobalSize16(pSeg
->hSeg
)) break;
374 offset
= next_offset
;
375 } while (offset
!= 0xffff);
383 WARN_(fixup
)("WARNING: %d: unknown ADDR TYPE %d, "
384 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
385 i
+ 1, rep
->address_type
, rep
->relocation_type
,
386 rep
->offset
, rep
->target1
, rep
->target2
);
392 /***********************************************************************
395 BOOL
NE_LoadAllSegments( NE_MODULE
*pModule
)
398 SEGTABLEENTRY
* pSegTable
= (SEGTABLEENTRY
*) NE_SEG_TABLE(pModule
);
400 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
404 /* Handle self-loading modules */
405 SELFLOADHEADER
*selfloadheader
;
406 STACK16FRAME
*stack16Top
;
407 THDB
*thdb
= THREAD_Current();
408 HMODULE16 hselfload
= GetModuleHandle16("WPROCS");
410 WORD saved_hSeg
= pSegTable
[pModule
->dgroup
- 1].hSeg
;
412 TRACE_(module
)("%.*s is a self-loading module!\n",
413 *((BYTE
*)pModule
+ pModule
->name_table
),
414 (char *)pModule
+ pModule
->name_table
+ 1);
415 if (!NE_LoadSegment( pModule
, 1 )) return FALSE
;
416 selfloadheader
= (SELFLOADHEADER
*)
417 PTR_SEG_OFF_TO_LIN(SEL(pSegTable
->hSeg
), 0);
418 selfloadheader
->EntryAddrProc
= NE_GetEntryPoint(hselfload
,27);
419 selfloadheader
->MyAlloc
= NE_GetEntryPoint(hselfload
,28);
420 selfloadheader
->SetOwner
= NE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
421 pModule
->self_loading_sel
= SEL(GLOBAL_Alloc(GMEM_ZEROINIT
, 0xFF00, pModule
->self
, FALSE
, FALSE
, FALSE
));
422 oldstack
= thdb
->cur_stack
;
423 thdb
->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
424 0xff00 - sizeof(*stack16Top
) );
425 stack16Top
= (STACK16FRAME
*)PTR_SEG_TO_LIN(thdb
->cur_stack
);
426 stack16Top
->frame32
= 0;
428 stack16Top
->ds
= stack16Top
->es
= pModule
->self_loading_sel
;
429 stack16Top
->entry_point
= 0;
430 stack16Top
->entry_ip
= 0;
431 stack16Top
->entry_cs
= 0;
436 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule
),
437 GetCurrentProcess(), &hf
, 0, FALSE
, DUPLICATE_SAME_ACCESS
);
438 hFile16
= FILE_AllocDosHandle( hf
);
439 TRACE_(dll
)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
440 pModule
->self
,hFile16
);
441 Callbacks
->CallBootAppProc(selfloadheader
->BootApp
, pModule
->self
,hFile16
);
442 TRACE_(dll
)("Return from CallBootAppProc\n");
444 /* some BootApp procs overwrite the segment handle of dgroup */
445 pSegTable
[pModule
->dgroup
- 1].hSeg
= saved_hSeg
;
446 thdb
->cur_stack
= oldstack
;
448 for (i
= 2; i
<= pModule
->seg_count
; i
++)
449 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
453 for (i
= 1; i
<= pModule
->seg_count
; i
++)
454 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
460 /***********************************************************************
461 * NE_FixupSegmentPrologs
463 * Fixup exported functions prologs of one segment
465 void NE_FixupSegmentPrologs(NE_MODULE
*pModule
, WORD segnum
)
467 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE( pModule
);
470 WORD dgroup
, num_entries
, sel
= SEL(pSegTable
[segnum
-1].hSeg
);
473 TRACE_(module
)("(%d);\n", segnum
);
475 if (pSegTable
[segnum
-1].flags
& NE_SEGFLAGS_DATA
)
477 pSegTable
[segnum
-1].flags
|= NE_SEGFLAGS_LOADED
;
480 if (!(dgroup
= SEL(pSegTable
[pModule
->dgroup
-1].hSeg
)))
483 pSeg
= PTR_SEG_OFF_TO_LIN(sel
, 0);
485 bundle
= (ET_BUNDLE
*)((BYTE
*)pModule
+pModule
->entry_table
);
488 TRACE_(module
)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle
->last
- bundle
->first
, bundle
, bundle
->next
, pSeg
);
489 if (!(num_entries
= bundle
->last
- bundle
->first
))
491 entry
= (ET_ENTRY
*)((BYTE
*)bundle
+6);
492 while (num_entries
--)
494 /*TRACE(module, "entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
495 if (entry
->segnum
== segnum
)
497 pFunc
= ((BYTE
*)pSeg
+entry
->offs
);
498 TRACE_(module
)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc
, *(DWORD
*)pFunc
, num_entries
);
499 if (*(pFunc
+2) == 0x90)
501 if (*(WORD
*)pFunc
== 0x581e) /* push ds, pop ax */
503 TRACE_(module
)("patch %04x:%04x -> mov ax, ds\n", sel
, entry
->offs
);
504 *(WORD
*)pFunc
= 0xd88c; /* mov ax, ds */
507 if (*(WORD
*)pFunc
== 0xd88c)
509 if ((entry
->flags
& 2)) /* public data ? */
511 TRACE_(module
)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel
, entry
->offs
, dgroup
);
512 *pFunc
= 0xb8; /* mov ax, */
513 *(WORD
*)(pFunc
+1) = dgroup
;
516 if ((pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
)
517 && (entry
->flags
& 1)) /* exported ? */
519 TRACE_(module
)("patch %04x:%04x -> nop, nop\n", sel
, entry
->offs
);
520 *(WORD
*)pFunc
= 0x9090; /* nop, nop */
527 } while ( (bundle
->next
)
528 && (bundle
= ((ET_BUNDLE
*)((BYTE
*)pModule
+ bundle
->next
))) );
532 /***********************************************************************
535 * Needed for self-loading modules.
537 DWORD WINAPI
PatchCodeHandle16(HANDLE16 hSeg
)
540 WORD sel
= SEL(hSeg
);
541 NE_MODULE
*pModule
= NE_GetPtr(FarGetOwner16(sel
));
542 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE(pModule
);
544 TRACE_(module
)("(%04x);\n", hSeg
);
546 /* find the segment number of the module that belongs to hSeg */
547 for (segnum
= 1; segnum
<= pModule
->seg_count
; segnum
++)
549 if (SEL(pSegTable
[segnum
-1].hSeg
) == sel
)
551 NE_FixupSegmentPrologs(pModule
, segnum
);
556 return MAKELONG(hSeg
, sel
);
559 /***********************************************************************
562 * Fixup the exported functions prologs.
564 void NE_FixupPrologs( NE_MODULE
*pModule
)
568 TRACE_(module
)("(%04x)\n", pModule
->self
);
570 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
571 NE_FixupSegmentPrologs(pModule
, 1);
573 for (segnum
=1; segnum
<= pModule
->seg_count
; segnum
++)
574 NE_FixupSegmentPrologs(pModule
, segnum
);
577 /***********************************************************************
578 * NE_GetDLLInitParams
580 static VOID
NE_GetDLLInitParams( NE_MODULE
*pModule
,
581 WORD
*hInst
, WORD
*ds
, WORD
*heap
)
583 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE( pModule
);
585 if (!(pModule
->flags
& NE_FFLAGS_SINGLEDATA
))
587 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
|| pModule
->dgroup
)
590 ERR_(dll
)("Library is not marked SINGLEDATA\n");
593 else /* DATA NONE DLL */
599 else /* DATA SINGLE DLL */
601 if (pModule
->dgroup
) {
602 *ds
= SEL(pSegTable
[pModule
->dgroup
-1].hSeg
);
603 *heap
= pModule
->heap_size
;
605 else /* hmm, DLL has no dgroup,
606 but why has it NE_FFLAGS_SINGLEDATA set ?
607 Buggy DLL compiler ? */
614 *hInst
= *ds
? *ds
: pModule
->self
;
618 /***********************************************************************
621 * Call the DLL initialization code
623 static BOOL
NE_InitDLL( TDB
* pTask
, NE_MODULE
*pModule
)
625 SEGTABLEENTRY
*pSegTable
;
626 WORD hInst
, ds
, heap
;
629 pSegTable
= NE_SEG_TABLE( pModule
);
631 if (!(pModule
->flags
& NE_FFLAGS_LIBMODULE
) ||
632 (pModule
->flags
& NE_FFLAGS_WIN32
)) return TRUE
; /*not a library*/
634 /* Call USER signal handler for Win3.1 compatibility. */
635 if (pTask
&& pTask
->userhandler
)
636 pTask
->userhandler( pModule
->self
, USIG16_DLL_LOAD
, 0,
637 pTask
->hInstance
, pTask
->hQueue
);
639 if (!pModule
->cs
) return TRUE
; /* no initialization code */
642 /* Registers at initialization must be:
644 * di library instance
645 * ds data segment if any
646 * es:si command line (always 0)
649 memset( &context
, 0, sizeof(context
) );
651 NE_GetDLLInitParams( pModule
, &hInst
, &ds
, &heap
);
653 ECX_reg(&context
) = heap
;
654 EDI_reg(&context
) = hInst
;
655 DS_reg(&context
) = ds
;
656 ES_reg(&context
) = ds
; /* who knows ... */
658 CS_reg(&context
) = SEL(pSegTable
[pModule
->cs
-1].hSeg
);
659 EIP_reg(&context
) = pModule
->ip
;
660 EBP_reg(&context
) = OFFSETOF(THREAD_Current()->cur_stack
)
661 + (WORD
)&((STACK16FRAME
*)0)->bp
;
664 pModule
->cs
= 0; /* Don't initialize it twice */
665 TRACE_(dll
)("Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
666 CS_reg(&context
), IP_reg(&context
), DS_reg(&context
),
667 DI_reg(&context
), CX_reg(&context
) );
668 Callbacks
->CallRegisterShortProc( &context
, 0 );
672 /***********************************************************************
673 * NE_CallDllEntryPoint
675 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
678 static void NE_CallDllEntryPoint( NE_MODULE
*pModule
, DWORD dwReason
)
680 WORD hInst
, ds
, heap
;
681 FARPROC16 entryPoint
;
684 THDB
*thdb
= THREAD_Current();
685 LPBYTE stack
= (LPBYTE
)THREAD_STACK16(thdb
);
687 if (!(pModule
->flags
& NE_FFLAGS_BUILTIN
) && pModule
->expected_version
< 0x0400) return;
688 if (!(ordinal
= NE_GetOrdinal( pModule
->self
, "DllEntryPoint" ))) return;
689 if (!(entryPoint
= NE_GetEntryPoint( pModule
->self
, ordinal
))) return;
691 memset( &context
, 0, sizeof(context
) );
693 NE_GetDLLInitParams( pModule
, &hInst
, &ds
, &heap
);
695 DS_reg(&context
) = ds
;
696 ES_reg(&context
) = ds
; /* who knows ... */
698 CS_reg(&context
) = HIWORD(entryPoint
);
699 IP_reg(&context
) = LOWORD(entryPoint
);
700 EBP_reg(&context
) = OFFSETOF( thdb
->cur_stack
)
701 + (WORD
)&((STACK16FRAME
*)0)->bp
;
703 *(DWORD
*)(stack
- 4) = dwReason
; /* dwReason */
704 *(WORD
*) (stack
- 6) = hInst
; /* hInst */
705 *(WORD
*) (stack
- 8) = ds
; /* wDS */
706 *(WORD
*) (stack
- 10) = heap
; /* wHeapSize */
707 *(DWORD
*)(stack
- 14) = 0; /* dwReserved1 */
708 *(WORD
*) (stack
- 16) = 0; /* wReserved2 */
710 TRACE_(dll
)("Calling DllEntryPoint, cs:ip=%04lx:%04x\n",
711 CS_reg(&context
), IP_reg(&context
));
713 Callbacks
->CallRegisterShortProc( &context
, 16 );
717 /***********************************************************************
720 * Recursively initialize all DLLs (according to the order in which
721 * they where loaded).
723 void NE_InitializeDLLs( HMODULE16 hModule
)
725 TDB
* pTask
= (TDB
*)GlobalLock16(GetCurrentTask());
729 if (!(pModule
= NE_GetPtr( hModule
))) return;
730 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
732 if (pModule
->dlls_to_init
)
734 HGLOBAL16 to_init
= pModule
->dlls_to_init
;
735 pModule
->dlls_to_init
= 0;
736 for (pDLL
= (HMODULE16
*)GlobalLock16( to_init
); *pDLL
; pDLL
++)
738 NE_InitializeDLLs( *pDLL
);
740 GlobalFree16( to_init
);
742 NE_InitDLL( pTask
, pModule
);
743 NE_CallDllEntryPoint( pModule
, DLL_PROCESS_ATTACH
);
747 /***********************************************************************
750 * If lib_only is TRUE, handle the module like a library even if it is a .EXE
752 HINSTANCE16
NE_CreateInstance( NE_MODULE
*pModule
, HINSTANCE16
*prev
,
755 SEGTABLEENTRY
*pSegment
;
757 HINSTANCE16 hNewInstance
;
759 if (pModule
->dgroup
== 0)
761 if (prev
) *prev
= pModule
->self
;
762 return pModule
->self
;
765 pSegment
= NE_SEG_TABLE( pModule
) + pModule
->dgroup
- 1;
766 if (prev
) *prev
= SEL(pSegment
->hSeg
);
768 /* if it's a library, create a new instance only the first time */
771 if (pModule
->flags
& NE_FFLAGS_LIBMODULE
) return SEL(pSegment
->hSeg
);
772 if (lib_only
) return SEL(pSegment
->hSeg
);
775 minsize
= pSegment
->minsize
? pSegment
->minsize
: 0x10000;
776 if (pModule
->ss
== pModule
->dgroup
) minsize
+= pModule
->stack_size
;
777 minsize
+= pModule
->heap_size
;
778 hNewInstance
= GLOBAL_Alloc( GMEM_ZEROINIT
| GMEM_FIXED
, minsize
,
779 pModule
->self
, FALSE
, FALSE
, FALSE
);
780 if (!hNewInstance
) return 0;
781 pSegment
->hSeg
= hNewInstance
;
782 pSegment
->flags
|= NE_SEGFLAGS_ALLOCATED
;
787 /***********************************************************************
790 * This function translates NE segment flags to GlobalAlloc flags
792 static WORD
NE_Ne2MemFlags(WORD flags
)
796 if (flags
& NE_SEGFLAGS_DISCARDABLE
)
797 memflags
|= GMEM_DISCARDABLE
;
798 if (flags
& NE_SEGFLAGS_MOVEABLE
||
799 ( ! (flags
& NE_SEGFLAGS_DATA
) &&
800 ! (flags
& NE_SEGFLAGS_LOADED
) &&
801 ! (flags
& NE_SEGFLAGS_ALLOCATED
)
804 memflags
|= GMEM_MOVEABLE
;
805 memflags
|= GMEM_ZEROINIT
;
807 memflags
= GMEM_ZEROINIT
| GMEM_FIXED
;
812 /***********************************************************************
813 * NE_AllocateSegment (WPROCS.26)
815 * MyAlloc() function for self-loading apps.
817 DWORD WINAPI
NE_AllocateSegment( WORD wFlags
, WORD wSize
, WORD wElem
)
819 WORD size
= wSize
<< wElem
;
822 if (wSize
|| (wFlags
& NE_SEGFLAGS_MOVEABLE
))
823 hMem
= GlobalAlloc16( NE_Ne2MemFlags(wFlags
), size
);
825 if ( ((wFlags
& 0x7) != 0x1) && /* DATA */
826 ((wFlags
& 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
828 WORD hSel
= SEL(hMem
);
829 WORD access
= SelectorAccessRights16(hSel
,0,0);
831 access
|= 2<<2; /* SEGMENT_CODE */
832 SelectorAccessRights16(hSel
,1,access
);
835 return MAKELONG( hMem
, SEL(hMem
) );
837 return MAKELONG( 0, hMem
);
841 /***********************************************************************
844 BOOL
NE_CreateSegments( NE_MODULE
*pModule
)
846 SEGTABLEENTRY
*pSegment
;
847 int i
, minsize
, seg_count
;
849 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
851 pSegment
= NE_SEG_TABLE( pModule
);
853 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
856 seg_count
= pModule
->seg_count
;
857 for (i
= 1; i
<= seg_count
; i
++, pSegment
++)
859 minsize
= pSegment
->minsize
? pSegment
->minsize
: 0x10000;
860 if (i
== pModule
->ss
) minsize
+= pModule
->stack_size
;
861 /* The DGROUP is allocated by NE_CreateInstance */
862 if (i
== pModule
->dgroup
) continue;
863 pSegment
->hSeg
= GLOBAL_Alloc( NE_Ne2MemFlags(pSegment
->flags
),
864 minsize
, pModule
->self
,
865 !(pSegment
->flags
& NE_SEGFLAGS_DATA
),
867 FALSE
/*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
868 if (!pSegment
->hSeg
) return FALSE
;
869 pSegment
->flags
|= NE_SEGFLAGS_ALLOCATED
;
872 pModule
->dgroup_entry
= pModule
->dgroup
? pModule
->seg_table
+
873 (pModule
->dgroup
- 1) * sizeof(SEGTABLEENTRY
) : 0;
878 /**********************************************************************
879 * IsSharedSelector (KERNEL.345)
881 BOOL16 WINAPI
IsSharedSelector16( HANDLE16 selector
)
883 /* Check whether the selector belongs to a DLL */
884 NE_MODULE
*pModule
= NE_GetPtr( selector
);
885 if (!pModule
) return FALSE
;
886 return (pModule
->flags
& NE_FFLAGS_LIBMODULE
) != 0;