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"
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 /***********************************************************************
42 static const char *NE_GetRelocAddrName( BYTE addr_type
, int additive
)
44 switch(addr_type
& 0x7f)
46 case NE_RADDR_LOWBYTE
: return additive
? "BYTE add" : "BYTE";
47 case NE_RADDR_OFFSET16
: return additive
? "OFFSET16 add" : "OFFSET16";
48 case NE_RADDR_POINTER32
: return additive
? "POINTER32 add" : "POINTER32";
49 case NE_RADDR_SELECTOR
: return additive
? "SELECTOR add" : "SELECTOR";
50 case NE_RADDR_POINTER48
: return additive
? "POINTER48 add" : "POINTER48";
51 case NE_RADDR_OFFSET32
: return additive
? "OFFSET32 add" : "OFFSET32";
57 /***********************************************************************
60 BOOL
NE_LoadSegment( NE_MODULE
*pModule
, WORD segnum
)
62 SEGTABLEENTRY
*pSegTable
, *pSeg
;
64 WORD count
, i
, offset
, next_offset
;
66 FARPROC16 address
= 0;
69 struct relocation_entry_s
*rep
, *reloc_entries
;
75 int ordinal
, additive
;
78 pSegTable
= NE_SEG_TABLE( pModule
);
79 pSeg
= pSegTable
+ segnum
- 1;
81 if (pSeg
->flags
& NE_SEGFLAGS_LOADED
) /* already loaded ? */
84 if (!pSeg
->filepos
) return TRUE
; /* No file image, just return */
86 pModuleTable
= NE_MODULE_TABLE( pModule
);
88 hf
= NE_OpenFile( pModule
);
89 TRACE_(module
)("Loading segment %d, hSeg=%04x, flags=%04x\n",
90 segnum
, pSeg
->hSeg
, pSeg
->flags
);
91 SetFilePointer( hf
, pSeg
->filepos
<< pModule
->alignment
, NULL
, SEEK_SET
);
92 if (pSeg
->size
) size
= pSeg
->size
;
93 else size
= pSeg
->minsize
? pSeg
->minsize
: 0x10000;
94 mem
= GlobalLock16(pSeg
->hSeg
);
95 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
&& segnum
> 1)
97 /* Implement self-loading segments */
98 SELFLOADHEADER
*selfloadheader
;
100 WORD old_hSeg
, new_hSeg
;
104 selfloadheader
= (SELFLOADHEADER
*)
105 PTR_SEG_OFF_TO_LIN(SEL(pSegTable
->hSeg
),0);
106 oldstack
= NtCurrentTeb()->cur_stack
;
107 old_hSeg
= pSeg
->hSeg
;
108 NtCurrentTeb()->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
109 0xff00 - sizeof(STACK16FRAME
));
111 TRACE_(dll
)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
112 pModule
->self
,hf
,segnum
);
113 DuplicateHandle( GetCurrentProcess(), hf
, GetCurrentProcess(), &hFile32
,
114 0, FALSE
, DUPLICATE_SAME_ACCESS
);
115 hFile16
= FILE_AllocDosHandle( hFile32
);
116 new_hSeg
= Callbacks
->CallLoadAppSegProc(selfloadheader
->LoadAppSeg
,
117 pModule
->self
, hFile16
,
119 TRACE_(dll
)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n",new_hSeg
);
120 _lclose16( hFile16
);
121 if (SEL(new_hSeg
) != SEL(old_hSeg
)) {
122 /* Self loaders like creating their own selectors;
123 * they love asking for trouble to Wine developers
125 if (segnum
== pModule
->dgroup
) {
126 memcpy(PTR_SEG_OFF_TO_LIN(SEL(old_hSeg
),0),
127 PTR_SEG_OFF_TO_LIN(SEL(new_hSeg
),0),
128 pSeg
->minsize
? pSeg
->minsize
: 0x10000);
129 FreeSelector16(SEL(new_hSeg
));
130 pSeg
->hSeg
= old_hSeg
;
131 TRACE_(module
)("New hSeg allocated for dgroup segment:Old=%d,New=%d\n",
134 FreeSelector16(SEL(pSeg
->hSeg
));
135 pSeg
->hSeg
= new_hSeg
;
139 NtCurrentTeb()->cur_stack
= oldstack
;
141 else if (!(pSeg
->flags
& NE_SEGFLAGS_ITERATED
))
142 ReadFile(hf
, mem
, size
, &res
, NULL
);
145 The following bit of code for "iterated segments" was written without
146 any documentation on the format of these segments. It seems to work,
147 but may be missing something. If you have any doc please either send
148 it to me or fix the code yourself. gfm@werple.mira.net.au
150 char* buff
= xmalloc(size
);
152 ReadFile(hf
, buff
, size
, &res
, NULL
);
153 while(curr
< buff
+ size
) {
154 unsigned int rept
= *((short*) curr
)++;
155 unsigned int len
= *((short*) curr
)++;
156 for(; rept
> 0; rept
--) {
159 for(byte
= 0; byte
< len
; byte
++)
167 pSeg
->flags
|= NE_SEGFLAGS_LOADED
;
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
*)xmalloc(count
* sizeof(struct relocation_entry_s
));
184 if (!ReadFile( hf
, reloc_entries
, count
* sizeof(struct relocation_entry_s
), &res
, NULL
) ||
185 (res
!= count
* sizeof(struct relocation_entry_s
)))
187 WARN_(fixup
)("Unable to read relocation information\n" );
192 * Go through the relocation table one entry at a time.
195 for (i
= 0; i
< count
; i
++, rep
++)
198 * Get the target address corresponding to this entry.
201 /* If additive, there is no target chain list. Instead, add source
203 additive
= rep
->relocation_type
& NE_RELFLAG_ADDITIVE
;
204 rep
->relocation_type
&= 0x3;
206 switch (rep
->relocation_type
)
208 case NE_RELTYPE_ORDINAL
:
209 module
= pModuleTable
[rep
->target1
-1];
210 ordinal
= rep
->target2
;
211 address
= NE_GetEntryPoint( module
, ordinal
);
214 NE_MODULE
*pTarget
= NE_GetPtr( module
);
216 WARN_(module
)("Module not found: %04x, reference %d of module %*.*s\n",
217 module
, rep
->target1
,
218 *((BYTE
*)pModule
+ pModule
->name_table
),
219 *((BYTE
*)pModule
+ pModule
->name_table
),
220 (char *)pModule
+ pModule
->name_table
+ 1 );
223 ERR_(fixup
)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
224 *((BYTE
*)pTarget
+ pTarget
->name_table
),
225 (char *)pTarget
+ pTarget
->name_table
+ 1,
227 address
= (FARPROC16
)0xdeadbeef;
232 NE_MODULE
*pTarget
= NE_GetPtr( module
);
233 TRACE_(fixup
)("%d: %.*s.%d=%04x:%04x %s\n", i
+ 1,
234 *((BYTE
*)pTarget
+ pTarget
->name_table
),
235 (char *)pTarget
+ pTarget
->name_table
+ 1,
236 ordinal
, HIWORD(address
), LOWORD(address
),
237 NE_GetRelocAddrName( rep
->address_type
, additive
) );
241 case NE_RELTYPE_NAME
:
242 module
= pModuleTable
[rep
->target1
-1];
243 func_name
= (char *)pModule
+ pModule
->import_table
+ rep
->target2
;
244 memcpy( buffer
, func_name
+1, *func_name
);
245 buffer
[*func_name
] = '\0';
247 ordinal
= NE_GetOrdinal( module
, func_name
);
248 address
= NE_GetEntryPoint( module
, ordinal
);
250 if (ERR_ON(fixup
) && !address
)
252 NE_MODULE
*pTarget
= NE_GetPtr( module
);
253 ERR_(fixup
)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
254 *((BYTE
*)pTarget
+ pTarget
->name_table
),
255 (char *)pTarget
+ pTarget
->name_table
+ 1, func_name
);
257 if (!address
) address
= (FARPROC16
) 0xdeadbeef;
260 NE_MODULE
*pTarget
= NE_GetPtr( module
);
261 TRACE_(fixup
)("%d: %.*s.%s=%04x:%04x %s\n", i
+ 1,
262 *((BYTE
*)pTarget
+ pTarget
->name_table
),
263 (char *)pTarget
+ pTarget
->name_table
+ 1,
264 func_name
, HIWORD(address
), LOWORD(address
),
265 NE_GetRelocAddrName( rep
->address_type
, additive
) );
269 case NE_RELTYPE_INTERNAL
:
270 if ((rep
->target1
& 0xff) == 0xff)
272 address
= NE_GetEntryPoint( pModule
->self
, rep
->target2
);
276 address
= (FARPROC16
)PTR_SEG_OFF_TO_SEGPTR( SEL(pSegTable
[rep
->target1
-1].hSeg
), rep
->target2
);
279 TRACE_(fixup
)("%d: %04x:%04x %s\n",
280 i
+ 1, HIWORD(address
), LOWORD(address
),
281 NE_GetRelocAddrName( rep
->address_type
, additive
) );
284 case NE_RELTYPE_OSFIXUP
:
285 /* Relocation type 7:
287 * These appear to be used as fixups for the Windows
288 * floating point emulator. Let's just ignore them and
289 * try to use the hardware floating point. Linux should
290 * successfully emulate the coprocessor if it doesn't
293 TRACE_(fixup
)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
294 i
+ 1, rep
->relocation_type
, rep
->offset
,
295 rep
->target1
, rep
->target2
,
296 NE_GetRelocAddrName( rep
->address_type
, additive
) );
300 offset
= rep
->offset
;
302 /* Apparently, high bit of address_type is sometimes set; */
303 /* we ignore it for now */
304 if (rep
->address_type
> NE_RADDR_OFFSET32
)
307 GetModuleName16( pModule
->self
, module
, sizeof(module
) );
308 ERR_(fixup
)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
309 module
, rep
->address_type
);
314 sp
= PTR_SEG_OFF_TO_LIN( SEL(pSeg
->hSeg
), offset
);
315 TRACE_(fixup
)(" %04x:%04x\n", offset
, *sp
);
316 switch (rep
->address_type
& 0x7f)
318 case NE_RADDR_LOWBYTE
:
319 *(BYTE
*)sp
+= LOBYTE((int)address
);
321 case NE_RADDR_OFFSET16
:
322 *sp
+= LOWORD(address
);
324 case NE_RADDR_POINTER32
:
325 *sp
+= LOWORD(address
);
326 *(sp
+1) = HIWORD(address
);
328 case NE_RADDR_SELECTOR
:
329 /* Borland creates additive records with offset zero. Strange, but OK */
331 ERR_(fixup
)("Additive selector to %04x.Please report\n",*sp
);
333 *sp
= HIWORD(address
);
339 else /* non-additive fixup */
343 sp
= PTR_SEG_OFF_TO_LIN( SEL(pSeg
->hSeg
), offset
);
345 TRACE_(fixup
)(" %04x:%04x\n", offset
, *sp
);
346 switch (rep
->address_type
& 0x7f)
348 case NE_RADDR_LOWBYTE
:
349 *(BYTE
*)sp
= LOBYTE((int)address
);
351 case NE_RADDR_OFFSET16
:
352 *sp
= LOWORD(address
);
354 case NE_RADDR_POINTER32
:
355 *(FARPROC16
*)sp
= address
;
357 case NE_RADDR_SELECTOR
:
358 *sp
= SELECTOROF(address
);
363 if (next_offset
== offset
) break; /* avoid infinite loop */
364 if (next_offset
>= GlobalSize16(pSeg
->hSeg
)) break;
365 offset
= next_offset
;
366 } while (offset
!= 0xffff);
374 WARN_(fixup
)("WARNING: %d: unknown ADDR TYPE %d, "
375 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
376 i
+ 1, rep
->address_type
, rep
->relocation_type
,
377 rep
->offset
, rep
->target1
, rep
->target2
);
383 /***********************************************************************
386 BOOL
NE_LoadAllSegments( NE_MODULE
*pModule
)
389 SEGTABLEENTRY
* pSegTable
= (SEGTABLEENTRY
*) NE_SEG_TABLE(pModule
);
391 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
395 /* Handle self-loading modules */
396 SELFLOADHEADER
*selfloadheader
;
397 HMODULE16 hselfload
= GetModuleHandle16("WPROCS");
399 WORD saved_hSeg
= pSegTable
[pModule
->dgroup
- 1].hSeg
;
401 TRACE_(module
)("%.*s is a self-loading module!\n",
402 *((BYTE
*)pModule
+ pModule
->name_table
),
403 (char *)pModule
+ pModule
->name_table
+ 1);
404 if (!NE_LoadSegment( pModule
, 1 )) return FALSE
;
405 selfloadheader
= (SELFLOADHEADER
*)
406 PTR_SEG_OFF_TO_LIN(SEL(pSegTable
->hSeg
), 0);
407 selfloadheader
->EntryAddrProc
= NE_GetEntryPoint(hselfload
,27);
408 selfloadheader
->MyAlloc
= NE_GetEntryPoint(hselfload
,28);
409 selfloadheader
->SetOwner
= NE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
410 pModule
->self_loading_sel
= SEL(GLOBAL_Alloc(GMEM_ZEROINIT
, 0xFF00, pModule
->self
, FALSE
, FALSE
, FALSE
));
411 oldstack
= NtCurrentTeb()->cur_stack
;
412 NtCurrentTeb()->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
413 0xff00 - sizeof(STACK16FRAME
) );
415 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule
),
416 GetCurrentProcess(), &hf
, 0, FALSE
, DUPLICATE_SAME_ACCESS
);
417 hFile16
= FILE_AllocDosHandle( hf
);
418 TRACE_(dll
)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
419 pModule
->self
,hFile16
);
420 Callbacks
->CallBootAppProc(selfloadheader
->BootApp
, pModule
->self
,hFile16
);
421 TRACE_(dll
)("Return from CallBootAppProc\n");
423 /* some BootApp procs overwrite the segment handle of dgroup */
424 pSegTable
[pModule
->dgroup
- 1].hSeg
= saved_hSeg
;
425 NtCurrentTeb()->cur_stack
= oldstack
;
427 for (i
= 2; i
<= pModule
->seg_count
; i
++)
428 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
432 for (i
= 1; i
<= pModule
->seg_count
; i
++)
433 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
439 /***********************************************************************
440 * NE_FixupSegmentPrologs
442 * Fixup exported functions prologs of one segment
444 void NE_FixupSegmentPrologs(NE_MODULE
*pModule
, WORD segnum
)
446 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE( pModule
);
449 WORD dgroup
, num_entries
, sel
= SEL(pSegTable
[segnum
-1].hSeg
);
452 TRACE_(module
)("(%d);\n", segnum
);
454 if (pSegTable
[segnum
-1].flags
& NE_SEGFLAGS_DATA
)
456 pSegTable
[segnum
-1].flags
|= NE_SEGFLAGS_LOADED
;
460 if (!pModule
->dgroup
) return;
462 if (!(dgroup
= SEL(pSegTable
[pModule
->dgroup
-1].hSeg
))) return;
464 pSeg
= PTR_SEG_OFF_TO_LIN(sel
, 0);
466 bundle
= (ET_BUNDLE
*)((BYTE
*)pModule
+pModule
->entry_table
);
469 TRACE_(module
)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle
->last
- bundle
->first
, bundle
, bundle
->next
, pSeg
);
470 if (!(num_entries
= bundle
->last
- bundle
->first
))
472 entry
= (ET_ENTRY
*)((BYTE
*)bundle
+6);
473 while (num_entries
--)
475 /*TRACE(module, "entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
476 if (entry
->segnum
== segnum
)
478 pFunc
= ((BYTE
*)pSeg
+entry
->offs
);
479 TRACE_(module
)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc
, *(DWORD
*)pFunc
, num_entries
);
480 if (*(pFunc
+2) == 0x90)
482 if (*(WORD
*)pFunc
== 0x581e) /* push ds, pop ax */
484 TRACE_(module
)("patch %04x:%04x -> mov ax, ds\n", sel
, entry
->offs
);
485 *(WORD
*)pFunc
= 0xd88c; /* mov ax, ds */
488 if (*(WORD
*)pFunc
== 0xd88c)
490 if ((entry
->flags
& 2)) /* public data ? */
492 TRACE_(module
)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel
, entry
->offs
, dgroup
);
493 *pFunc
= 0xb8; /* mov ax, */
494 *(WORD
*)(pFunc
+1) = dgroup
;
497 if ((pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
)
498 && (entry
->flags
& 1)) /* exported ? */
500 TRACE_(module
)("patch %04x:%04x -> nop, nop\n", sel
, entry
->offs
);
501 *(WORD
*)pFunc
= 0x9090; /* nop, nop */
508 } while ( (bundle
->next
)
509 && (bundle
= ((ET_BUNDLE
*)((BYTE
*)pModule
+ bundle
->next
))) );
513 /***********************************************************************
516 * Needed for self-loading modules.
518 DWORD WINAPI
PatchCodeHandle16(HANDLE16 hSeg
)
521 WORD sel
= SEL(hSeg
);
522 NE_MODULE
*pModule
= NE_GetPtr(FarGetOwner16(sel
));
523 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE(pModule
);
525 TRACE_(module
)("(%04x);\n", hSeg
);
527 /* find the segment number of the module that belongs to hSeg */
528 for (segnum
= 1; segnum
<= pModule
->seg_count
; segnum
++)
530 if (SEL(pSegTable
[segnum
-1].hSeg
) == sel
)
532 NE_FixupSegmentPrologs(pModule
, segnum
);
537 return MAKELONG(hSeg
, sel
);
540 /***********************************************************************
543 * Fixup the exported functions prologs.
545 void NE_FixupPrologs( NE_MODULE
*pModule
)
549 TRACE_(module
)("(%04x)\n", pModule
->self
);
551 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
552 NE_FixupSegmentPrologs(pModule
, 1);
554 for (segnum
=1; segnum
<= pModule
->seg_count
; segnum
++)
555 NE_FixupSegmentPrologs(pModule
, segnum
);
558 /***********************************************************************
559 * NE_GetDLLInitParams
561 static VOID
NE_GetDLLInitParams( NE_MODULE
*pModule
,
562 WORD
*hInst
, WORD
*ds
, WORD
*heap
)
564 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE( pModule
);
566 if (!(pModule
->flags
& NE_FFLAGS_SINGLEDATA
))
568 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
|| pModule
->dgroup
)
571 ERR_(dll
)("Library is not marked SINGLEDATA\n");
574 else /* DATA NONE DLL */
580 else /* DATA SINGLE DLL */
582 if (pModule
->dgroup
) {
583 *ds
= SEL(pSegTable
[pModule
->dgroup
-1].hSeg
);
584 *heap
= pModule
->heap_size
;
586 else /* hmm, DLL has no dgroup,
587 but why has it NE_FFLAGS_SINGLEDATA set ?
588 Buggy DLL compiler ? */
595 *hInst
= *ds
? *ds
: pModule
->self
;
599 /***********************************************************************
602 * Call the DLL initialization code
604 static BOOL
NE_InitDLL( TDB
* pTask
, NE_MODULE
*pModule
)
606 SEGTABLEENTRY
*pSegTable
;
607 WORD hInst
, ds
, heap
;
610 pSegTable
= NE_SEG_TABLE( pModule
);
612 if (!(pModule
->flags
& NE_FFLAGS_LIBMODULE
) ||
613 (pModule
->flags
& NE_FFLAGS_WIN32
)) return TRUE
; /*not a library*/
615 /* Call USER signal handler for Win3.1 compatibility. */
616 if (pTask
&& pTask
->userhandler
)
617 pTask
->userhandler( pModule
->self
, USIG16_DLL_LOAD
, 0,
618 pTask
->hInstance
, pTask
->hQueue
);
620 if (!pModule
->cs
) return TRUE
; /* no initialization code */
623 /* Registers at initialization must be:
625 * di library instance
626 * ds data segment if any
627 * es:si command line (always 0)
630 memset( &context
, 0, sizeof(context
) );
632 NE_GetDLLInitParams( pModule
, &hInst
, &ds
, &heap
);
634 ECX_reg(&context
) = heap
;
635 EDI_reg(&context
) = hInst
;
636 DS_reg(&context
) = ds
;
637 ES_reg(&context
) = ds
; /* who knows ... */
639 CS_reg(&context
) = SEL(pSegTable
[pModule
->cs
-1].hSeg
);
640 EIP_reg(&context
) = pModule
->ip
;
641 EBP_reg(&context
) = OFFSETOF(NtCurrentTeb()->cur_stack
) + (WORD
)&((STACK16FRAME
*)0)->bp
;
644 pModule
->cs
= 0; /* Don't initialize it twice */
645 TRACE_(dll
)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
646 CS_reg(&context
), EIP_reg(&context
), DS_reg(&context
),
647 DI_reg(&context
), CX_reg(&context
) );
648 Callbacks
->CallRegisterShortProc( &context
, 0 );
652 /***********************************************************************
653 * NE_CallDllEntryPoint
655 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
658 static void NE_CallDllEntryPoint( NE_MODULE
*pModule
, DWORD dwReason
)
660 WORD hInst
, ds
, heap
;
661 FARPROC16 entryPoint
;
664 LPBYTE stack
= (LPBYTE
)CURRENT_STACK16
;
666 if (!(pModule
->flags
& NE_FFLAGS_BUILTIN
) && pModule
->expected_version
< 0x0400) return;
667 if (!(ordinal
= NE_GetOrdinal( pModule
->self
, "DllEntryPoint" ))) return;
668 if (!(entryPoint
= NE_GetEntryPoint( pModule
->self
, ordinal
))) return;
670 memset( &context
, 0, sizeof(context
) );
672 NE_GetDLLInitParams( pModule
, &hInst
, &ds
, &heap
);
674 DS_reg(&context
) = ds
;
675 ES_reg(&context
) = ds
; /* who knows ... */
677 CS_reg(&context
) = HIWORD(entryPoint
);
678 EIP_reg(&context
) = LOWORD(entryPoint
);
679 EBP_reg(&context
) = OFFSETOF( NtCurrentTeb()->cur_stack
)
680 + (WORD
)&((STACK16FRAME
*)0)->bp
;
682 *(DWORD
*)(stack
- 4) = dwReason
; /* dwReason */
683 *(WORD
*) (stack
- 6) = hInst
; /* hInst */
684 *(WORD
*) (stack
- 8) = ds
; /* wDS */
685 *(WORD
*) (stack
- 10) = heap
; /* wHeapSize */
686 *(DWORD
*)(stack
- 14) = 0; /* dwReserved1 */
687 *(WORD
*) (stack
- 16) = 0; /* wReserved2 */
689 TRACE_(dll
)("Calling DllEntryPoint, cs:ip=%04lx:%04lx\n",
690 CS_reg(&context
), EIP_reg(&context
));
692 Callbacks
->CallRegisterShortProc( &context
, 16 );
696 /***********************************************************************
699 * Recursively initialize all DLLs (according to the order in which
700 * they where loaded).
702 void NE_InitializeDLLs( HMODULE16 hModule
)
704 TDB
* pTask
= (TDB
*)GlobalLock16(GetCurrentTask());
708 if (!(pModule
= NE_GetPtr( hModule
))) return;
709 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
711 if (pModule
->dlls_to_init
)
713 HGLOBAL16 to_init
= pModule
->dlls_to_init
;
714 pModule
->dlls_to_init
= 0;
715 for (pDLL
= (HMODULE16
*)GlobalLock16( to_init
); *pDLL
; pDLL
++)
717 NE_InitializeDLLs( *pDLL
);
719 GlobalFree16( to_init
);
721 NE_InitDLL( pTask
, pModule
);
722 NE_CallDllEntryPoint( pModule
, DLL_PROCESS_ATTACH
);
726 /***********************************************************************
729 * This function translates NE segment flags to GlobalAlloc flags
731 static WORD
NE_Ne2MemFlags(WORD flags
)
735 if (flags
& NE_SEGFLAGS_DISCARDABLE
)
736 memflags
|= GMEM_DISCARDABLE
;
737 if (flags
& NE_SEGFLAGS_MOVEABLE
||
738 ( ! (flags
& NE_SEGFLAGS_DATA
) &&
739 ! (flags
& NE_SEGFLAGS_LOADED
) &&
740 ! (flags
& NE_SEGFLAGS_ALLOCATED
)
743 memflags
|= GMEM_MOVEABLE
;
744 memflags
|= GMEM_ZEROINIT
;
746 memflags
= GMEM_ZEROINIT
| GMEM_FIXED
;
752 /***********************************************************************
755 * If lib_only is TRUE, handle the module like a library even if it is a .EXE
757 HINSTANCE16
NE_CreateInstance( NE_MODULE
*pModule
, HINSTANCE16
*prev
,
760 SEGTABLEENTRY
*pSegment
;
764 if (pModule
->dgroup
== 0)
766 if (prev
) *prev
= pModule
->self
;
767 return pModule
->self
;
770 pSegment
= NE_SEG_TABLE( pModule
) + pModule
->dgroup
- 1;
771 if (prev
) *prev
= SEL(pSegment
->hSeg
);
773 /* if it's a library, create a new instance only the first time */
776 if (pModule
->flags
& NE_FFLAGS_LIBMODULE
) return SEL(pSegment
->hSeg
);
777 if (lib_only
) return SEL(pSegment
->hSeg
);
780 minsize
= pSegment
->minsize
? pSegment
->minsize
: 0x10000;
781 if (pModule
->ss
== pModule
->dgroup
) minsize
+= pModule
->stack_size
;
782 minsize
+= pModule
->heap_size
;
783 hNewSeg
= GLOBAL_Alloc( NE_Ne2MemFlags(pSegment
->flags
), minsize
,
784 pModule
->self
, FALSE
, FALSE
, FALSE
);
785 if (!hNewSeg
) return 0;
786 pSegment
->hSeg
= hNewSeg
;
787 pSegment
->flags
|= NE_SEGFLAGS_ALLOCATED
;
789 /* a HINSTANCE is the selector of the DSEG */
790 return (HINSTANCE16
)SEL(hNewSeg
);
794 /***********************************************************************
795 * NE_AllocateSegment (WPROCS.26)
797 * MyAlloc() function for self-loading apps.
799 DWORD WINAPI
NE_AllocateSegment( WORD wFlags
, WORD wSize
, WORD wElem
)
801 WORD size
= wSize
<< wElem
;
804 if (wSize
|| (wFlags
& NE_SEGFLAGS_MOVEABLE
))
805 hMem
= GlobalAlloc16( NE_Ne2MemFlags(wFlags
), size
);
807 if ( ((wFlags
& 0x7) != 0x1) && /* DATA */
808 ((wFlags
& 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
810 WORD hSel
= SEL(hMem
);
811 WORD access
= SelectorAccessRights16(hSel
,0,0);
813 access
|= 2<<2; /* SEGMENT_CODE */
814 SelectorAccessRights16(hSel
,1,access
);
817 return MAKELONG( hMem
, SEL(hMem
) );
819 return MAKELONG( 0, hMem
);
823 /***********************************************************************
826 BOOL
NE_CreateSegments( NE_MODULE
*pModule
)
828 SEGTABLEENTRY
*pSegment
;
829 int i
, minsize
, seg_count
;
831 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
833 pSegment
= NE_SEG_TABLE( pModule
);
835 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
838 seg_count
= pModule
->seg_count
;
839 for (i
= 1; i
<= seg_count
; i
++, pSegment
++)
841 minsize
= pSegment
->minsize
? pSegment
->minsize
: 0x10000;
842 if (i
== pModule
->ss
) minsize
+= pModule
->stack_size
;
843 /* The DGROUP is allocated by NE_CreateInstance */
844 if (i
== pModule
->dgroup
) continue;
845 pSegment
->hSeg
= GLOBAL_Alloc( NE_Ne2MemFlags(pSegment
->flags
),
846 minsize
, pModule
->self
,
847 !(pSegment
->flags
& NE_SEGFLAGS_DATA
),
848 (pSegment
->flags
& NE_SEGFLAGS_32BIT
) != 0,
849 FALSE
/*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
850 if (!pSegment
->hSeg
) return FALSE
;
851 pSegment
->flags
|= NE_SEGFLAGS_ALLOCATED
;
854 pModule
->dgroup_entry
= pModule
->dgroup
? pModule
->seg_table
+
855 (pModule
->dgroup
- 1) * sizeof(SEGTABLEENTRY
) : 0;
860 /**********************************************************************
861 * IsSharedSelector (KERNEL.345)
863 BOOL16 WINAPI
IsSharedSelector16( HANDLE16 selector
)
865 /* Check whether the selector belongs to a DLL */
866 NE_MODULE
*pModule
= NE_GetPtr( selector
);
867 if (!pModule
) return FALSE
;
868 return (pModule
->flags
& NE_FFLAGS_LIBMODULE
) != 0;