4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
11 #include <sys/types.h>
18 #include "wine/winbase16.h"
23 #include "stackframe.h"
24 #include "builtin16.h"
25 #include "debugtools.h"
27 DECLARE_DEBUG_CHANNEL(dll
);
28 DECLARE_DEBUG_CHANNEL(fixup
);
29 DECLARE_DEBUG_CHANNEL(module
);
30 DECLARE_DEBUG_CHANNEL(segment
);
33 * Relocation table entry
35 struct relocation_entry_s
37 BYTE address_type
; /* Relocation address type */
38 BYTE relocation_type
; /* Relocation type */
39 WORD offset
; /* Offset in segment to fixup */
40 WORD target1
; /* Target specification */
41 WORD target2
; /* Target specification */
45 * Relocation address types
47 #define NE_RADDR_LOWBYTE 0
48 #define NE_RADDR_SELECTOR 2
49 #define NE_RADDR_POINTER32 3
50 #define NE_RADDR_OFFSET16 5
51 #define NE_RADDR_POINTER48 11
52 #define NE_RADDR_OFFSET32 13
57 #define NE_RELTYPE_INTERNAL 0
58 #define NE_RELTYPE_ORDINAL 1
59 #define NE_RELTYPE_NAME 2
60 #define NE_RELTYPE_OSFIXUP 3
61 #define NE_RELFLAG_ADDITIVE 4
63 #define SEL(x) ((x)|1)
65 static void NE_FixupSegmentPrologs(NE_MODULE
*pModule
, WORD segnum
);
67 /* ### start build ### */
68 extern WORD CALLBACK
NE_CallTo16_word_ww(FARPROC16
,WORD
,WORD
);
69 extern WORD CALLBACK
NE_CallTo16_word_www(FARPROC16
,WORD
,WORD
,WORD
);
70 /* ### stop build ### */
72 /***********************************************************************
75 static const char *NE_GetRelocAddrName( BYTE addr_type
, int additive
)
77 switch(addr_type
& 0x7f)
79 case NE_RADDR_LOWBYTE
: return additive
? "BYTE add" : "BYTE";
80 case NE_RADDR_OFFSET16
: return additive
? "OFFSET16 add" : "OFFSET16";
81 case NE_RADDR_POINTER32
: return additive
? "POINTER32 add" : "POINTER32";
82 case NE_RADDR_SELECTOR
: return additive
? "SELECTOR add" : "SELECTOR";
83 case NE_RADDR_POINTER48
: return additive
? "POINTER48 add" : "POINTER48";
84 case NE_RADDR_OFFSET32
: return additive
? "OFFSET32 add" : "OFFSET32";
90 /***********************************************************************
93 BOOL
NE_LoadSegment( NE_MODULE
*pModule
, WORD segnum
)
95 SEGTABLEENTRY
*pSegTable
, *pSeg
;
97 WORD count
, i
, offset
, next_offset
;
99 FARPROC16 address
= 0;
102 struct relocation_entry_s
*rep
, *reloc_entries
;
108 int ordinal
, additive
;
111 pSegTable
= NE_SEG_TABLE( pModule
);
112 pSeg
= pSegTable
+ segnum
- 1;
114 if (pSeg
->flags
& NE_SEGFLAGS_LOADED
)
116 /* self-loader ? -> already loaded it */
117 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
120 /* leave, except for DGROUP, as this may be the second instance */
121 if (segnum
!= pModule
->dgroup
)
125 if (!pSeg
->filepos
) return TRUE
; /* No file image, just return */
127 pModuleTable
= NE_MODULE_TABLE( pModule
);
129 hf
= NE_OpenFile( pModule
);
130 TRACE_(module
)("Loading segment %d, hSeg=%04x, flags=%04x\n",
131 segnum
, pSeg
->hSeg
, pSeg
->flags
);
132 SetFilePointer( hf
, pSeg
->filepos
<< pModule
->alignment
, NULL
, SEEK_SET
);
133 if (pSeg
->size
) size
= pSeg
->size
;
134 else size
= pSeg
->minsize
? pSeg
->minsize
: 0x10000;
135 mem
= GlobalLock16(pSeg
->hSeg
);
136 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
&& segnum
> 1)
138 /* Implement self-loading segments */
139 SELFLOADHEADER
*selfloadheader
;
144 selfloadheader
= (SELFLOADHEADER
*)
145 PTR_SEG_OFF_TO_LIN(SEL(pSegTable
->hSeg
),0);
146 oldstack
= NtCurrentTeb()->cur_stack
;
147 NtCurrentTeb()->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(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
)PTR_SEG_OFF_TO_SEGPTR( 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
= 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 *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
= PTR_SEG_OFF_TO_LIN( 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
)
429 /* Handle self-loading modules */
430 SELFLOADHEADER
*selfloadheader
;
431 HMODULE16 mod
= GetModuleHandle16("KERNEL");
434 TRACE_(module
)("%.*s is a self-loading module!\n",
435 *((BYTE
*)pModule
+ pModule
->name_table
),
436 (char *)pModule
+ pModule
->name_table
+ 1);
437 if (!NE_LoadSegment( pModule
, 1 )) return FALSE
;
438 selfloadheader
= (SELFLOADHEADER
*)
439 PTR_SEG_OFF_TO_LIN(SEL(pSegTable
->hSeg
), 0);
440 selfloadheader
->EntryAddrProc
= GetProcAddress16(mod
,"EntryAddrProc");
441 selfloadheader
->MyAlloc
= GetProcAddress16(mod
,"MyAlloc");
442 selfloadheader
->SetOwner
= GetProcAddress16(mod
,"FarSetOwner");
443 pModule
->self_loading_sel
= SEL(GLOBAL_Alloc(GMEM_ZEROINIT
, 0xFF00, pModule
->self
, WINE_LDT_FLAGS_DATA
));
444 oldstack
= NtCurrentTeb()->cur_stack
;
445 NtCurrentTeb()->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
446 0xff00 - sizeof(STACK16FRAME
) );
448 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule
),
449 GetCurrentProcess(), &hf
, 0, FALSE
, DUPLICATE_SAME_ACCESS
);
450 hFile16
= Win32HandleToDosFileHandle( hf
);
451 TRACE_(dll
)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
452 pModule
->self
,hFile16
);
453 NE_CallTo16_word_ww(selfloadheader
->BootApp
, pModule
->self
,hFile16
);
454 TRACE_(dll
)("Return from CallBootAppProc\n");
456 NtCurrentTeb()->cur_stack
= oldstack
;
458 for (i
= 2; i
<= pModule
->seg_count
; i
++)
459 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
463 for (i
= 1; i
<= pModule
->seg_count
; i
++)
464 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
470 /***********************************************************************
471 * NE_FixupSegmentPrologs
473 * Fixup exported functions prologs of one segment
475 static void NE_FixupSegmentPrologs(NE_MODULE
*pModule
, WORD segnum
)
477 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE( pModule
);
480 WORD dgroup
, num_entries
, sel
= SEL(pSegTable
[segnum
-1].hSeg
);
483 TRACE_(module
)("(%d);\n", segnum
);
485 if (pSegTable
[segnum
-1].flags
& NE_SEGFLAGS_DATA
)
487 pSegTable
[segnum
-1].flags
|= NE_SEGFLAGS_LOADED
;
491 if (!pModule
->dgroup
) return;
493 if (!(dgroup
= SEL(pSegTable
[pModule
->dgroup
-1].hSeg
))) return;
495 pSeg
= PTR_SEG_OFF_TO_LIN(sel
, 0);
497 bundle
= (ET_BUNDLE
*)((BYTE
*)pModule
+pModule
->entry_table
);
500 TRACE_(module
)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle
->last
- bundle
->first
, bundle
, bundle
->next
, pSeg
);
501 if (!(num_entries
= bundle
->last
- bundle
->first
))
503 entry
= (ET_ENTRY
*)((BYTE
*)bundle
+6);
504 while (num_entries
--)
506 /*TRACE_(module)("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
507 if (entry
->segnum
== segnum
)
509 pFunc
= ((BYTE
*)pSeg
+entry
->offs
);
510 TRACE_(module
)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc
, *(DWORD
*)pFunc
, num_entries
);
511 if (*(pFunc
+2) == 0x90)
513 if (*(WORD
*)pFunc
== 0x581e) /* push ds, pop ax */
515 TRACE_(module
)("patch %04x:%04x -> mov ax, ds\n", sel
, entry
->offs
);
516 *(WORD
*)pFunc
= 0xd88c; /* mov ax, ds */
519 if (*(WORD
*)pFunc
== 0xd88c)
521 if ((entry
->flags
& 2)) /* public data ? */
523 TRACE_(module
)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel
, entry
->offs
, dgroup
);
524 *pFunc
= 0xb8; /* mov ax, */
525 *(WORD
*)(pFunc
+1) = dgroup
;
528 if ((pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
)
529 && (entry
->flags
& 1)) /* exported ? */
531 TRACE_(module
)("patch %04x:%04x -> nop, nop\n", sel
, entry
->offs
);
532 *(WORD
*)pFunc
= 0x9090; /* nop, nop */
539 } while ( (bundle
->next
)
540 && (bundle
= ((ET_BUNDLE
*)((BYTE
*)pModule
+ bundle
->next
))) );
544 /***********************************************************************
547 * Needed for self-loading modules.
549 DWORD WINAPI
PatchCodeHandle16(HANDLE16 hSeg
)
552 WORD sel
= SEL(hSeg
);
553 NE_MODULE
*pModule
= NE_GetPtr(FarGetOwner16(sel
));
554 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE(pModule
);
556 TRACE_(module
)("(%04x);\n", hSeg
);
558 /* find the segment number of the module that belongs to hSeg */
559 for (segnum
= 1; segnum
<= pModule
->seg_count
; segnum
++)
561 if (SEL(pSegTable
[segnum
-1].hSeg
) == sel
)
563 NE_FixupSegmentPrologs(pModule
, segnum
);
568 return MAKELONG(hSeg
, sel
);
572 /***********************************************************************
573 * NE_GetDLLInitParams
575 static VOID
NE_GetDLLInitParams( NE_MODULE
*pModule
,
576 WORD
*hInst
, WORD
*ds
, WORD
*heap
)
578 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE( pModule
);
580 if (!(pModule
->flags
& NE_FFLAGS_SINGLEDATA
))
582 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
|| pModule
->dgroup
)
585 ERR_(dll
)("Library is not marked SINGLEDATA\n");
588 else /* DATA NONE DLL */
594 else /* DATA SINGLE DLL */
596 if (pModule
->dgroup
) {
597 *ds
= SEL(pSegTable
[pModule
->dgroup
-1].hSeg
);
598 *heap
= pModule
->heap_size
;
600 else /* hmm, DLL has no dgroup,
601 but why has it NE_FFLAGS_SINGLEDATA set ?
602 Buggy DLL compiler ? */
609 *hInst
= *ds
? GlobalHandle16(*ds
) : pModule
->self
;
613 /***********************************************************************
616 * Call the DLL initialization code
618 static BOOL
NE_InitDLL( TDB
* pTask
, NE_MODULE
*pModule
)
620 SEGTABLEENTRY
*pSegTable
;
621 WORD hInst
, ds
, heap
;
624 pSegTable
= NE_SEG_TABLE( pModule
);
626 if (!(pModule
->flags
& NE_FFLAGS_LIBMODULE
) ||
627 (pModule
->flags
& NE_FFLAGS_WIN32
)) return TRUE
; /*not a library*/
629 /* Call USER signal handler for Win3.1 compatibility. */
630 TASK_CallTaskSignalProc( USIG16_DLL_LOAD
, pModule
->self
);
632 if (!pModule
->cs
) return TRUE
; /* no initialization code */
635 /* Registers at initialization must be:
637 * di library instance
638 * ds data segment if any
639 * es:si command line (always 0)
642 memset( &context
, 0, sizeof(context
) );
644 NE_GetDLLInitParams( pModule
, &hInst
, &ds
, &heap
);
649 context
.SegEs
= ds
; /* who knows ... */
651 context
.SegCs
= SEL(pSegTable
[pModule
->cs
-1].hSeg
);
652 context
.Eip
= pModule
->ip
;
653 context
.Ebp
= OFFSETOF(NtCurrentTeb()->cur_stack
) + (WORD
)&((STACK16FRAME
*)0)->bp
;
656 pModule
->cs
= 0; /* Don't initialize it twice */
657 TRACE_(dll
)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
658 context
.SegCs
, context
.Eip
, context
.SegDs
,
659 LOWORD(context
.Edi
), LOWORD(context
.Ecx
) );
660 wine_call_to_16_regs_short( &context
, 0 );
664 /***********************************************************************
667 * Recursively initialize all DLLs (according to the order in which
668 * they where loaded).
670 void NE_InitializeDLLs( HMODULE16 hModule
)
672 TDB
* pTask
= (TDB
*)GlobalLock16(GetCurrentTask());
676 if (!(pModule
= NE_GetPtr( hModule
))) return;
677 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
679 if (pModule
->dlls_to_init
)
681 HGLOBAL16 to_init
= pModule
->dlls_to_init
;
682 pModule
->dlls_to_init
= 0;
683 for (pDLL
= (HMODULE16
*)GlobalLock16( to_init
); *pDLL
; pDLL
++)
685 NE_InitializeDLLs( *pDLL
);
687 GlobalFree16( to_init
);
689 NE_InitDLL( pTask
, pModule
);
693 /***********************************************************************
694 * NE_CallDllEntryPoint
696 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
698 typedef DWORD
WINAPI (*WinNEEntryProc
)(DWORD
,WORD
,WORD
,WORD
,DWORD
,WORD
);
700 static void NE_CallDllEntryPoint( NE_MODULE
*pModule
, DWORD dwReason
)
702 WORD hInst
, ds
, heap
;
703 FARPROC16 entryPoint
;
705 if (!(pModule
->flags
& NE_FFLAGS_LIBMODULE
)) return;
706 if (!(pModule
->flags
& NE_FFLAGS_BUILTIN
) && pModule
->expected_version
< 0x0400) return;
707 if (!(entryPoint
= GetProcAddress16( pModule
->self
, "DllEntryPoint" ))) return;
709 NE_GetDLLInitParams( pModule
, &hInst
, &ds
, &heap
);
711 TRACE_(dll
)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
712 NE_MODULE_NAME( pModule
),
713 SELECTOROF(entryPoint
), OFFSETOF(entryPoint
) );
715 if ( pModule
->flags
& NE_FFLAGS_BUILTIN
)
717 WinNEEntryProc entryProc
= (WinNEEntryProc
)
718 ((ENTRYPOINT16
*)PTR_SEG_TO_LIN( 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
768 void NE_DllProcessAttach( HMODULE16 hModule
)
774 if (!(pModule
= NE_GetPtr( hModule
))) return;
775 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
777 /* Check for recursive call */
778 if ( pModule
->misc_flags
& 0x80 ) return;
780 TRACE_(dll
)("(%s) - START\n", NE_MODULE_NAME(pModule
) );
782 /* Tag current module to prevent recursive loop */
783 pModule
->misc_flags
|= 0x80;
785 /* Recursively attach all DLLs this one depends on */
786 pModRef
= NE_MODULE_TABLE( pModule
);
787 for ( i
= 0; i
< pModule
->modref_count
; i
++ )
789 NE_DllProcessAttach( (HMODULE16
)pModRef
[i
] );
791 /* Call DLL entry point */
792 NE_CallDllEntryPoint( pModule
, DLL_PROCESS_ATTACH
);
794 /* Remove recursion flag */
795 pModule
->misc_flags
&= ~0x80;
797 TRACE_(dll
)("(%s) - END\n", NE_MODULE_NAME(pModule
) );
801 /***********************************************************************
804 * This function translates NE segment flags to GlobalAlloc flags
806 static WORD
NE_Ne2MemFlags(WORD flags
)
810 if (flags
& NE_SEGFLAGS_DISCARDABLE
)
811 memflags
|= GMEM_DISCARDABLE
;
812 if (flags
& NE_SEGFLAGS_MOVEABLE
||
813 ( ! (flags
& NE_SEGFLAGS_DATA
) &&
814 ! (flags
& NE_SEGFLAGS_LOADED
) &&
815 ! (flags
& NE_SEGFLAGS_ALLOCATED
)
818 memflags
|= GMEM_MOVEABLE
;
819 memflags
|= GMEM_ZEROINIT
;
821 memflags
= GMEM_ZEROINIT
| GMEM_FIXED
;
826 /***********************************************************************
827 * MyAlloc16 (KERNEL Wine-specific export)
829 * MyAlloc() function for self-loading apps.
831 DWORD WINAPI
MyAlloc16( WORD wFlags
, WORD wSize
, WORD wElem
)
833 WORD size
= wSize
<< wElem
;
836 if (wSize
|| (wFlags
& NE_SEGFLAGS_MOVEABLE
))
837 hMem
= GlobalAlloc16( NE_Ne2MemFlags(wFlags
), size
);
839 if ( ((wFlags
& 0x7) != 0x1) && /* DATA */
840 ((wFlags
& 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
842 WORD hSel
= SEL(hMem
);
843 WORD access
= SelectorAccessRights16(hSel
,0,0);
845 access
|= 2<<2; /* SEGMENT_CODE */
846 SelectorAccessRights16(hSel
,1,access
);
849 return MAKELONG( hMem
, SEL(hMem
) );
851 return MAKELONG( 0, hMem
);
854 /***********************************************************************
857 HINSTANCE16
NE_GetInstance( NE_MODULE
*pModule
)
859 if ( !pModule
->dgroup
)
860 return pModule
->self
;
864 pSeg
= NE_SEG_TABLE( pModule
) + pModule
->dgroup
- 1;
869 /***********************************************************************
872 BOOL
NE_CreateSegment( NE_MODULE
*pModule
, int segnum
)
874 SEGTABLEENTRY
*pSeg
= NE_SEG_TABLE( pModule
) + segnum
- 1;
876 unsigned char selflags
;
878 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
880 if ( segnum
< 1 || segnum
> pModule
->seg_count
)
883 if ( (pModule
->flags
& NE_FFLAGS_SELFLOAD
) && segnum
!= 1 )
884 return TRUE
; /* selfloader allocates segment itself */
886 if ( (pSeg
->flags
& NE_SEGFLAGS_ALLOCATED
) && segnum
!= pModule
->dgroup
)
887 return TRUE
; /* all but DGROUP only allocated once */
889 minsize
= pSeg
->minsize
? pSeg
->minsize
: 0x10000;
890 if ( segnum
== pModule
->ss
) minsize
+= pModule
->stack_size
;
891 if ( segnum
== pModule
->dgroup
) minsize
+= pModule
->heap_size
;
893 selflags
= (pSeg
->flags
& NE_SEGFLAGS_DATA
) ? WINE_LDT_FLAGS_DATA
: WINE_LDT_FLAGS_CODE
;
894 if (pSeg
->flags
& NE_SEGFLAGS_32BIT
) selflags
|= WINE_LDT_FLAGS_32BIT
;
895 pSeg
->hSeg
= GLOBAL_Alloc( NE_Ne2MemFlags(pSeg
->flags
), minsize
, pModule
->self
, selflags
);
896 if (!pSeg
->hSeg
) return FALSE
;
898 pSeg
->flags
|= NE_SEGFLAGS_ALLOCATED
;
902 /***********************************************************************
903 * NE_CreateAllSegments
905 BOOL
NE_CreateAllSegments( NE_MODULE
*pModule
)
908 for ( i
= 1; i
<= pModule
->seg_count
; i
++ )
909 if ( !NE_CreateSegment( pModule
, i
) )
912 pModule
->dgroup_entry
= pModule
->dgroup
? pModule
->seg_table
+
913 (pModule
->dgroup
- 1) * sizeof(SEGTABLEENTRY
) : 0;
918 /**********************************************************************
919 * IsSharedSelector (KERNEL.345)
921 BOOL16 WINAPI
IsSharedSelector16( HANDLE16 selector
)
923 /* Check whether the selector belongs to a DLL */
924 NE_MODULE
*pModule
= NE_GetPtr( selector
);
925 if (!pModule
) return FALSE
;
926 return (pModule
->flags
& NE_FFLAGS_LIBMODULE
) != 0;