4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "wine/port.h"
28 #include <sys/types.h>
36 #include "wine/winbase16.h"
37 #include "wine/library.h"
42 #include "stackframe.h"
43 #include "builtin16.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(fixup
);
47 WINE_DECLARE_DEBUG_CHANNEL(dll
);
48 WINE_DECLARE_DEBUG_CHANNEL(module
);
51 * Relocation table entry
53 struct relocation_entry_s
55 BYTE address_type
; /* Relocation address type */
56 BYTE relocation_type
; /* Relocation type */
57 WORD offset
; /* Offset in segment to fixup */
58 WORD target1
; /* Target specification */
59 WORD target2
; /* Target specification */
63 * Relocation address types
65 #define NE_RADDR_LOWBYTE 0
66 #define NE_RADDR_SELECTOR 2
67 #define NE_RADDR_POINTER32 3
68 #define NE_RADDR_OFFSET16 5
69 #define NE_RADDR_POINTER48 11
70 #define NE_RADDR_OFFSET32 13
75 #define NE_RELTYPE_INTERNAL 0
76 #define NE_RELTYPE_ORDINAL 1
77 #define NE_RELTYPE_NAME 2
78 #define NE_RELTYPE_OSFIXUP 3
79 #define NE_RELFLAG_ADDITIVE 4
81 #define SEL(x) ((x)|1)
83 static void NE_FixupSegmentPrologs(NE_MODULE
*pModule
, WORD segnum
);
85 /* ### start build ### */
86 extern WORD CALLBACK
NE_CallTo16_word_ww(FARPROC16
,WORD
,WORD
);
87 extern WORD CALLBACK
NE_CallTo16_word_www(FARPROC16
,WORD
,WORD
,WORD
);
88 /* ### stop build ### */
90 /***********************************************************************
93 static const char *NE_GetRelocAddrName( BYTE addr_type
, int additive
)
95 switch(addr_type
& 0x7f)
97 case NE_RADDR_LOWBYTE
: return additive
? "BYTE add" : "BYTE";
98 case NE_RADDR_OFFSET16
: return additive
? "OFFSET16 add" : "OFFSET16";
99 case NE_RADDR_POINTER32
: return additive
? "POINTER32 add" : "POINTER32";
100 case NE_RADDR_SELECTOR
: return additive
? "SELECTOR add" : "SELECTOR";
101 case NE_RADDR_POINTER48
: return additive
? "POINTER48 add" : "POINTER48";
102 case NE_RADDR_OFFSET32
: return additive
? "OFFSET32 add" : "OFFSET32";
108 /***********************************************************************
111 BOOL
NE_LoadSegment( NE_MODULE
*pModule
, WORD segnum
)
113 SEGTABLEENTRY
*pSegTable
, *pSeg
;
115 WORD count
, i
, offset
, next_offset
;
117 FARPROC16 address
= 0;
120 struct relocation_entry_s
*rep
, *reloc_entries
;
126 int ordinal
, additive
;
129 pSegTable
= NE_SEG_TABLE( pModule
);
130 pSeg
= pSegTable
+ segnum
- 1;
132 if (pSeg
->flags
& NE_SEGFLAGS_LOADED
)
134 /* self-loader ? -> already loaded it */
135 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
138 /* leave, except for DGROUP, as this may be the second instance */
139 if (segnum
!= pModule
->dgroup
)
143 if (!pSeg
->filepos
) return TRUE
; /* No file image, just return */
145 pModuleTable
= NE_MODULE_TABLE( pModule
);
147 hf
= NE_OpenFile( pModule
);
148 TRACE_(module
)("Loading segment %d, hSeg=%04x, flags=%04x\n",
149 segnum
, pSeg
->hSeg
, pSeg
->flags
);
150 SetFilePointer( hf
, pSeg
->filepos
<< pModule
->alignment
, NULL
, SEEK_SET
);
151 if (pSeg
->size
) size
= pSeg
->size
;
152 else size
= pSeg
->minsize
? pSeg
->minsize
: 0x10000;
153 mem
= GlobalLock16(pSeg
->hSeg
);
154 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
&& segnum
> 1)
156 /* Implement self-loading segments */
157 SELFLOADHEADER
*selfloadheader
;
162 selfloadheader
= MapSL( MAKESEGPTR(SEL(pSegTable
->hSeg
),0) );
163 oldstack
= NtCurrentTeb()->cur_stack
;
164 NtCurrentTeb()->cur_stack
= MAKESEGPTR(pModule
->self_loading_sel
,
165 0xff00 - sizeof(STACK16FRAME
));
167 TRACE_(dll
)("CallLoadAppSegProc(hmodule=0x%04x,hf=%p,segnum=%d\n",
168 pModule
->self
,hf
,segnum
);
169 DuplicateHandle( GetCurrentProcess(), hf
, GetCurrentProcess(), &hFile32
,
170 0, FALSE
, DUPLICATE_SAME_ACCESS
);
171 hFile16
= Win32HandleToDosFileHandle( hFile32
);
172 pSeg
->hSeg
= NE_CallTo16_word_www( selfloadheader
->LoadAppSeg
,
173 pModule
->self
, hFile16
, segnum
);
174 TRACE_(dll
)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg
->hSeg
);
175 _lclose16( hFile16
);
176 NtCurrentTeb()->cur_stack
= oldstack
;
178 else if (!(pSeg
->flags
& NE_SEGFLAGS_ITERATED
))
179 ReadFile(hf
, mem
, size
, &res
, NULL
);
182 The following bit of code for "iterated segments" was written without
183 any documentation on the format of these segments. It seems to work,
184 but may be missing something. If you have any doc please either send
185 it to me or fix the code yourself. gfm@werple.mira.net.au
187 char* buff
= HeapAlloc(GetProcessHeap(), 0, size
);
191 WARN_(dll
)("Memory exausted!");
195 ReadFile(hf
, buff
, size
, &res
, NULL
);
196 while(curr
< buff
+ size
) {
197 unsigned int rept
= *((short*) curr
)++;
198 unsigned int len
= *((short*) curr
)++;
199 for(; rept
> 0; rept
--) {
202 for(byte
= 0; byte
< len
; byte
++)
207 HeapFree(GetProcessHeap(), 0, buff
);
210 pSeg
->flags
|= NE_SEGFLAGS_LOADED
;
212 /* Perform exported function prolog fixups */
213 NE_FixupSegmentPrologs( pModule
, segnum
);
215 if (!(pSeg
->flags
& NE_SEGFLAGS_RELOC_DATA
))
216 goto succeed
; /* No relocation data, we are done */
218 ReadFile(hf
, &count
, sizeof(count
), &res
, NULL
);
219 if (!count
) goto succeed
;
221 TRACE("Fixups for %.*s, segment %d, hSeg %04x\n",
222 *((BYTE
*)pModule
+ pModule
->name_table
),
223 (char *)pModule
+ pModule
->name_table
+ 1,
224 segnum
, pSeg
->hSeg
);
226 reloc_entries
= (struct relocation_entry_s
*)HeapAlloc(GetProcessHeap(), 0, count
* sizeof(struct relocation_entry_s
));
227 if(reloc_entries
== NULL
) {
228 WARN("Not enough memory for relocation entries!");
231 if (!ReadFile( hf
, reloc_entries
, count
* sizeof(struct relocation_entry_s
), &res
, NULL
) ||
232 (res
!= count
* sizeof(struct relocation_entry_s
)))
234 WARN("Unable to read relocation information\n" );
239 * Go through the relocation table one entry at a time.
242 for (i
= 0; i
< count
; i
++, rep
++)
245 * Get the target address corresponding to this entry.
248 /* If additive, there is no target chain list. Instead, add source
250 additive
= rep
->relocation_type
& NE_RELFLAG_ADDITIVE
;
251 rep
->relocation_type
&= 0x3;
253 switch (rep
->relocation_type
)
255 case NE_RELTYPE_ORDINAL
:
256 module
= pModuleTable
[rep
->target1
-1];
257 ordinal
= rep
->target2
;
258 address
= NE_GetEntryPoint( module
, ordinal
);
261 NE_MODULE
*pTarget
= NE_GetPtr( module
);
263 WARN_(module
)("Module not found: %04x, reference %d of module %*.*s\n",
264 module
, rep
->target1
,
265 *((BYTE
*)pModule
+ pModule
->name_table
),
266 *((BYTE
*)pModule
+ pModule
->name_table
),
267 (char *)pModule
+ pModule
->name_table
+ 1 );
270 ERR("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
271 *((BYTE
*)pTarget
+ pTarget
->name_table
),
272 (char *)pTarget
+ pTarget
->name_table
+ 1,
274 address
= (FARPROC16
)0xdeadbeef;
279 NE_MODULE
*pTarget
= NE_GetPtr( module
);
280 TRACE("%d: %.*s.%d=%04x:%04x %s\n", i
+ 1,
281 *((BYTE
*)pTarget
+ pTarget
->name_table
),
282 (char *)pTarget
+ pTarget
->name_table
+ 1,
283 ordinal
, HIWORD(address
), LOWORD(address
),
284 NE_GetRelocAddrName( rep
->address_type
, additive
) );
288 case NE_RELTYPE_NAME
:
289 module
= pModuleTable
[rep
->target1
-1];
290 func_name
= (char *)pModule
+ pModule
->import_table
+ rep
->target2
;
291 memcpy( buffer
, func_name
+1, *func_name
);
292 buffer
[*func_name
] = '\0';
294 ordinal
= NE_GetOrdinal( module
, func_name
);
295 address
= NE_GetEntryPoint( module
, ordinal
);
297 if (ERR_ON(fixup
) && !address
)
299 NE_MODULE
*pTarget
= NE_GetPtr( module
);
300 ERR("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
301 *((BYTE
*)pTarget
+ pTarget
->name_table
),
302 (char *)pTarget
+ pTarget
->name_table
+ 1, func_name
);
304 if (!address
) address
= (FARPROC16
) 0xdeadbeef;
307 NE_MODULE
*pTarget
= NE_GetPtr( module
);
308 TRACE("%d: %.*s.%s=%04x:%04x %s\n", i
+ 1,
309 *((BYTE
*)pTarget
+ pTarget
->name_table
),
310 (char *)pTarget
+ pTarget
->name_table
+ 1,
311 func_name
, HIWORD(address
), LOWORD(address
),
312 NE_GetRelocAddrName( rep
->address_type
, additive
) );
316 case NE_RELTYPE_INTERNAL
:
317 if ((rep
->target1
& 0xff) == 0xff)
319 address
= NE_GetEntryPoint( pModule
->self
, rep
->target2
);
323 address
= (FARPROC16
)MAKESEGPTR( SEL(pSegTable
[rep
->target1
-1].hSeg
), rep
->target2
);
326 TRACE("%d: %04x:%04x %s\n",
327 i
+ 1, HIWORD(address
), LOWORD(address
),
328 NE_GetRelocAddrName( rep
->address_type
, additive
) );
331 case NE_RELTYPE_OSFIXUP
:
332 /* Relocation type 7:
334 * These appear to be used as fixups for the Windows
335 * floating point emulator. Let's just ignore them and
336 * try to use the hardware floating point. Linux should
337 * successfully emulate the coprocessor if it doesn't
340 TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
341 i
+ 1, rep
->relocation_type
, rep
->offset
,
342 rep
->target1
, rep
->target2
,
343 NE_GetRelocAddrName( rep
->address_type
, additive
) );
347 offset
= rep
->offset
;
349 /* Apparently, high bit of address_type is sometimes set; */
350 /* we ignore it for now */
351 if (rep
->address_type
> NE_RADDR_OFFSET32
)
354 GetModuleName16( pModule
->self
, module
, sizeof(module
) );
355 ERR("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
356 module
, rep
->address_type
);
361 sp
= MapSL( MAKESEGPTR( SEL(pSeg
->hSeg
), offset
) );
362 TRACE(" %04x:%04x\n", offset
, *sp
);
363 switch (rep
->address_type
& 0x7f)
365 case NE_RADDR_LOWBYTE
:
366 *(BYTE
*)sp
+= LOBYTE((int)address
);
368 case NE_RADDR_OFFSET16
:
369 *sp
+= LOWORD(address
);
371 case NE_RADDR_POINTER32
:
372 *sp
+= LOWORD(address
);
373 *(sp
+1) = HIWORD(address
);
375 case NE_RADDR_SELECTOR
:
376 /* Borland creates additive records with offset zero. Strange, but OK */
378 ERR("Additive selector to %04x.Please report\n",*sp
);
380 *sp
= HIWORD(address
);
386 else /* non-additive fixup */
390 sp
= MapSL( MAKESEGPTR( SEL(pSeg
->hSeg
), offset
) );
392 TRACE(" %04x:%04x\n", offset
, *sp
);
393 switch (rep
->address_type
& 0x7f)
395 case NE_RADDR_LOWBYTE
:
396 *(BYTE
*)sp
= LOBYTE((int)address
);
398 case NE_RADDR_OFFSET16
:
399 *sp
= LOWORD(address
);
401 case NE_RADDR_POINTER32
:
402 *(FARPROC16
*)sp
= address
;
404 case NE_RADDR_SELECTOR
:
405 *sp
= SELECTOROF(address
);
410 if (next_offset
== offset
) break; /* avoid infinite loop */
411 if (next_offset
>= GlobalSize16(pSeg
->hSeg
)) break;
412 offset
= next_offset
;
413 } while (offset
!= 0xffff);
417 HeapFree(GetProcessHeap(), 0, reloc_entries
);
424 WARN("WARNING: %d: unknown ADDR TYPE %d, "
425 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
426 i
+ 1, rep
->address_type
, rep
->relocation_type
,
427 rep
->offset
, rep
->target1
, rep
->target2
);
428 HeapFree(GetProcessHeap(), 0, reloc_entries
);
436 /***********************************************************************
439 BOOL
NE_LoadAllSegments( NE_MODULE
*pModule
)
442 SEGTABLEENTRY
* pSegTable
= (SEGTABLEENTRY
*) NE_SEG_TABLE(pModule
);
444 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
449 /* Handle self-loading modules */
450 SELFLOADHEADER
*selfloadheader
;
451 HMODULE16 mod
= GetModuleHandle16("KERNEL");
454 TRACE_(module
)("%.*s is a self-loading module!\n",
455 *((BYTE
*)pModule
+ pModule
->name_table
),
456 (char *)pModule
+ pModule
->name_table
+ 1);
457 if (!NE_LoadSegment( pModule
, 1 )) return FALSE
;
458 selfloadheader
= MapSL( MAKESEGPTR(SEL(pSegTable
->hSeg
), 0) );
459 selfloadheader
->EntryAddrProc
= GetProcAddress16(mod
,"EntryAddrProc");
460 selfloadheader
->MyAlloc
= GetProcAddress16(mod
,"MyAlloc");
461 selfloadheader
->SetOwner
= GetProcAddress16(mod
,"FarSetOwner");
462 sel
= GlobalAlloc16( GMEM_ZEROINIT
, 0xFF00 );
463 pModule
->self_loading_sel
= SEL(sel
);
464 FarSetOwner16( sel
, pModule
->self
);
465 oldstack
= NtCurrentTeb()->cur_stack
;
466 NtCurrentTeb()->cur_stack
= MAKESEGPTR(pModule
->self_loading_sel
,
467 0xff00 - sizeof(STACK16FRAME
) );
469 hf
= NE_OpenFile(pModule
);
470 hFile16
= Win32HandleToDosFileHandle( hf
);
471 TRACE_(dll
)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
472 pModule
->self
,hFile16
);
473 NE_CallTo16_word_ww(selfloadheader
->BootApp
, pModule
->self
,hFile16
);
474 TRACE_(dll
)("Return from CallBootAppProc\n");
476 NtCurrentTeb()->cur_stack
= oldstack
;
478 for (i
= 2; i
<= pModule
->seg_count
; i
++)
479 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
483 for (i
= 1; i
<= pModule
->seg_count
; i
++)
484 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
490 /***********************************************************************
491 * NE_FixupSegmentPrologs
493 * Fixup exported functions prologs of one segment
495 static void NE_FixupSegmentPrologs(NE_MODULE
*pModule
, WORD segnum
)
497 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE( pModule
);
500 WORD dgroup
, num_entries
, sel
= SEL(pSegTable
[segnum
-1].hSeg
);
503 TRACE("(%d);\n", segnum
);
505 if (pSegTable
[segnum
-1].flags
& NE_SEGFLAGS_DATA
)
507 pSegTable
[segnum
-1].flags
|= NE_SEGFLAGS_LOADED
;
511 if (!pModule
->dgroup
) return;
513 if (!(dgroup
= SEL(pSegTable
[pModule
->dgroup
-1].hSeg
))) return;
515 pSeg
= MapSL( MAKESEGPTR(sel
, 0) );
517 bundle
= (ET_BUNDLE
*)((BYTE
*)pModule
+pModule
->entry_table
);
520 TRACE("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle
->last
- bundle
->first
, bundle
, bundle
->next
, pSeg
);
521 if (!(num_entries
= bundle
->last
- bundle
->first
))
523 entry
= (ET_ENTRY
*)((BYTE
*)bundle
+6);
524 while (num_entries
--)
526 /*TRACE("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
527 if (entry
->segnum
== segnum
)
529 pFunc
= ((BYTE
*)pSeg
+entry
->offs
);
530 TRACE("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc
, *(DWORD
*)pFunc
, num_entries
);
531 if (*(pFunc
+2) == 0x90)
533 if (*(WORD
*)pFunc
== 0x581e) /* push ds, pop ax */
535 TRACE("patch %04x:%04x -> mov ax, ds\n", sel
, entry
->offs
);
536 *(WORD
*)pFunc
= 0xd88c; /* mov ax, ds */
539 if (*(WORD
*)pFunc
== 0xd88c)
541 if ((entry
->flags
& 2)) /* public data ? */
543 TRACE("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel
, entry
->offs
, dgroup
);
544 *pFunc
= 0xb8; /* mov ax, */
545 *(WORD
*)(pFunc
+1) = dgroup
;
548 if ((pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
)
549 && (entry
->flags
& 1)) /* exported ? */
551 TRACE("patch %04x:%04x -> nop, nop\n", sel
, entry
->offs
);
552 *(WORD
*)pFunc
= 0x9090; /* nop, nop */
559 } while ( (bundle
->next
)
560 && (bundle
= ((ET_BUNDLE
*)((BYTE
*)pModule
+ bundle
->next
))) );
564 /***********************************************************************
565 * PatchCodeHandle (KERNEL.110)
567 * Needed for self-loading modules.
569 DWORD WINAPI
PatchCodeHandle16(HANDLE16 hSeg
)
572 WORD sel
= SEL(hSeg
);
573 NE_MODULE
*pModule
= NE_GetPtr(FarGetOwner16(sel
));
574 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE(pModule
);
576 TRACE_(module
)("(%04x);\n", hSeg
);
578 /* find the segment number of the module that belongs to hSeg */
579 for (segnum
= 1; segnum
<= pModule
->seg_count
; segnum
++)
581 if (SEL(pSegTable
[segnum
-1].hSeg
) == sel
)
583 NE_FixupSegmentPrologs(pModule
, segnum
);
588 return MAKELONG(hSeg
, sel
);
592 /***********************************************************************
593 * NE_GetDLLInitParams
595 static VOID
NE_GetDLLInitParams( NE_MODULE
*pModule
,
596 WORD
*hInst
, WORD
*ds
, WORD
*heap
)
598 SEGTABLEENTRY
*pSegTable
= NE_SEG_TABLE( pModule
);
600 if (!(pModule
->flags
& NE_FFLAGS_SINGLEDATA
))
602 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
|| pModule
->dgroup
)
605 ERR_(dll
)("Library is not marked SINGLEDATA\n");
608 else /* DATA NONE DLL */
614 else /* DATA SINGLE DLL */
616 if (pModule
->dgroup
) {
617 *ds
= SEL(pSegTable
[pModule
->dgroup
-1].hSeg
);
618 *heap
= pModule
->heap_size
;
620 else /* hmm, DLL has no dgroup,
621 but why has it NE_FFLAGS_SINGLEDATA set ?
622 Buggy DLL compiler ? */
629 *hInst
= *ds
? GlobalHandle16(*ds
) : pModule
->self
;
633 /***********************************************************************
636 * Call the DLL initialization code
638 static BOOL
NE_InitDLL( NE_MODULE
*pModule
)
640 SEGTABLEENTRY
*pSegTable
;
641 WORD hInst
, ds
, heap
;
644 pSegTable
= NE_SEG_TABLE( pModule
);
646 if (!(pModule
->flags
& NE_FFLAGS_LIBMODULE
) ||
647 (pModule
->flags
& NE_FFLAGS_WIN32
)) return TRUE
; /*not a library*/
649 /* Call USER signal handler for Win3.1 compatibility. */
650 NE_CallUserSignalProc( pModule
->self
, USIG16_DLL_LOAD
);
652 if (!pModule
->cs
) return TRUE
; /* no initialization code */
655 /* Registers at initialization must be:
657 * di library instance
658 * ds data segment if any
659 * es:si command line (always 0)
662 memset( &context
, 0, sizeof(context
) );
664 NE_GetDLLInitParams( pModule
, &hInst
, &ds
, &heap
);
669 context
.SegEs
= ds
; /* who knows ... */
671 context
.SegCs
= SEL(pSegTable
[pModule
->cs
-1].hSeg
);
672 context
.Eip
= pModule
->ip
;
673 context
.Ebp
= OFFSETOF(NtCurrentTeb()->cur_stack
) + (WORD
)&((STACK16FRAME
*)0)->bp
;
676 pModule
->cs
= 0; /* Don't initialize it twice */
677 TRACE_(dll
)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
678 context
.SegCs
, context
.Eip
, context
.SegDs
,
679 LOWORD(context
.Edi
), LOWORD(context
.Ecx
) );
680 wine_call_to_16_regs_short( &context
, 0 );
684 /***********************************************************************
687 * Recursively initialize all DLLs (according to the order in which
688 * they where loaded).
690 void NE_InitializeDLLs( HMODULE16 hModule
)
695 if (!(pModule
= NE_GetPtr( hModule
))) return;
696 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
698 if (pModule
->dlls_to_init
)
700 HGLOBAL16 to_init
= pModule
->dlls_to_init
;
701 pModule
->dlls_to_init
= 0;
702 for (pDLL
= (HMODULE16
*)GlobalLock16( to_init
); *pDLL
; pDLL
++)
704 NE_InitializeDLLs( *pDLL
);
706 GlobalFree16( to_init
);
708 NE_InitDLL( pModule
);
712 /**********************************************************************
713 * NE_CallUserSignalProc
715 * According to "Undocumented Windows", the task signal proc is
716 * bypassed for module load/unload notifications, and the USER signal
717 * proc is called directly instead. This is what this function does.
719 typedef DWORD (WINAPI
*pSignalProc
)( HANDLE16 module
, UINT16 code
, UINT16 exit
,
720 HINSTANCE16 inst
, HQUEUE16 queue
);
722 void NE_CallUserSignalProc( HMODULE16 hModule
, UINT16 code
)
725 HMODULE16 user
= GetModuleHandle16("user.exe");
728 if ((proc
= GetProcAddress16( user
, "SignalProc" )))
730 /* USER is always a builtin dll */
731 pSignalProc sigproc
= (pSignalProc
)((ENTRYPOINT16
*)MapSL( (SEGPTR
)proc
))->target
;
732 sigproc( hModule
, code
, 0, 0, 0 );
737 /***********************************************************************
738 * NE_CallDllEntryPoint
740 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
742 typedef DWORD (WINAPI
*WinNEEntryProc
)(DWORD
,WORD
,WORD
,WORD
,DWORD
,WORD
);
744 static void NE_CallDllEntryPoint( NE_MODULE
*pModule
, DWORD dwReason
)
746 WORD hInst
, ds
, heap
;
747 FARPROC16 entryPoint
;
749 if (!(pModule
->flags
& NE_FFLAGS_LIBMODULE
)) return;
750 if (!(pModule
->flags
& NE_FFLAGS_BUILTIN
) && pModule
->expected_version
< 0x0400) return;
751 if (!(entryPoint
= GetProcAddress16( pModule
->self
, "DllEntryPoint" ))) return;
753 NE_GetDLLInitParams( pModule
, &hInst
, &ds
, &heap
);
755 TRACE_(dll
)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
756 NE_MODULE_NAME( pModule
),
757 SELECTOROF(entryPoint
), OFFSETOF(entryPoint
) );
759 if ( pModule
->flags
& NE_FFLAGS_BUILTIN
)
761 WinNEEntryProc entryProc
= (WinNEEntryProc
)((ENTRYPOINT16
*)MapSL( (SEGPTR
)entryPoint
))->target
;
763 entryProc( dwReason
, hInst
, ds
, heap
, 0, 0 );
767 LPBYTE stack
= (LPBYTE
)CURRENT_STACK16
;
770 memset( &context
, 0, sizeof(context
) );
772 context
.SegEs
= ds
; /* who knows ... */
774 context
.SegCs
= HIWORD(entryPoint
);
775 context
.Eip
= LOWORD(entryPoint
);
776 context
.Ebp
= OFFSETOF( NtCurrentTeb()->cur_stack
)
777 + (WORD
)&((STACK16FRAME
*)0)->bp
;
779 *(DWORD
*)(stack
- 4) = dwReason
; /* dwReason */
780 *(WORD
*) (stack
- 6) = hInst
; /* hInst */
781 *(WORD
*) (stack
- 8) = ds
; /* wDS */
782 *(WORD
*) (stack
- 10) = heap
; /* wHeapSize */
783 *(DWORD
*)(stack
- 14) = 0; /* dwReserved1 */
784 *(WORD
*) (stack
- 16) = 0; /* wReserved2 */
786 wine_call_to_16_regs_short( &context
, 16 );
790 /***********************************************************************
791 * NE_DllProcessAttach
793 * Call the DllEntryPoint of all modules this one (recursively)
794 * depends on, according to the order in which they were loaded.
796 * Note that --as opposed to the PE module case-- there is no notion
797 * of 'module loaded into a process' for NE modules, and hence we
798 * have no place to store the fact that the DllEntryPoint of a
799 * given module was already called on behalf of this process (e.g.
800 * due to some earlier LoadLibrary16 call).
802 * Thus, we just call the DllEntryPoint twice in that case. Win9x
803 * appears to behave this way as well ...
805 * This routine must only be called with the Win16Lock held.
807 * FIXME: We should actually abort loading in case the DllEntryPoint
819 static void add_to_init_list( struct ne_init_list
*list
, NE_MODULE
*hModule
)
821 if ( list
->count
== list
->size
)
823 int newSize
= list
->size
+ 128;
824 NE_MODULE
**newModule
= HeapReAlloc( GetProcessHeap(), 0,
825 list
->module
, newSize
*sizeof(NE_MODULE
*) );
828 FIXME_(dll
)("Out of memory!");
832 list
->module
= newModule
;
833 list
->size
= newSize
;
836 list
->module
[list
->count
++] = hModule
;
839 static void free_init_list( struct ne_init_list
*list
)
843 HeapFree( GetProcessHeap(), 0, list
->module
);
844 memset( list
, 0, sizeof(*list
) );
848 static void fill_init_list( struct ne_init_list
*list
, HMODULE16 hModule
)
854 if (!(pModule
= NE_GetPtr( hModule
))) return;
855 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
857 /* Never add a module twice */
858 for ( i
= 0; i
< list
->count
; i
++ )
859 if ( list
->module
[i
] == pModule
)
862 /* Check for recursive call */
863 if ( pModule
->misc_flags
& 0x80 ) return;
865 TRACE_(dll
)("(%s) - START\n", NE_MODULE_NAME(pModule
) );
867 /* Tag current module to prevent recursive loop */
868 pModule
->misc_flags
|= 0x80;
870 /* Recursively attach all DLLs this one depends on */
871 pModRef
= NE_MODULE_TABLE( pModule
);
872 for ( i
= 0; i
< pModule
->modref_count
; i
++ )
874 fill_init_list( list
, (HMODULE16
)pModRef
[i
] );
876 /* Add current module */
877 add_to_init_list( list
, pModule
);
879 /* Remove recursion flag */
880 pModule
->misc_flags
&= ~0x80;
882 TRACE_(dll
)("(%s) - END\n", NE_MODULE_NAME(pModule
) );
885 static void call_init_list( struct ne_init_list
*list
)
888 for ( i
= 0; i
< list
->count
; i
++ )
889 NE_CallDllEntryPoint( list
->module
[i
], DLL_PROCESS_ATTACH
);
892 void NE_DllProcessAttach( HMODULE16 hModule
)
894 struct ne_init_list list
;
895 memset( &list
, 0, sizeof(list
) );
897 fill_init_list( &list
, hModule
);
898 call_init_list( &list
);
899 free_init_list( &list
);
903 /***********************************************************************
906 * This function translates NE segment flags to GlobalAlloc flags
908 static WORD
NE_Ne2MemFlags(WORD flags
)
912 if (flags
& NE_SEGFLAGS_DISCARDABLE
)
913 memflags
|= GMEM_DISCARDABLE
;
914 if (flags
& NE_SEGFLAGS_MOVEABLE
||
915 ( ! (flags
& NE_SEGFLAGS_DATA
) &&
916 ! (flags
& NE_SEGFLAGS_LOADED
) &&
917 ! (flags
& NE_SEGFLAGS_ALLOCATED
)
920 memflags
|= GMEM_MOVEABLE
;
921 memflags
|= GMEM_ZEROINIT
;
923 memflags
= GMEM_ZEROINIT
| GMEM_FIXED
;
928 /***********************************************************************
929 * MyAlloc (KERNEL.668) Wine-specific export
931 * MyAlloc() function for self-loading apps.
933 DWORD WINAPI
MyAlloc16( WORD wFlags
, WORD wSize
, WORD wElem
)
935 WORD size
= wSize
<< wElem
;
938 if (wSize
|| (wFlags
& NE_SEGFLAGS_MOVEABLE
))
939 hMem
= GlobalAlloc16( NE_Ne2MemFlags(wFlags
), size
);
941 if ( ((wFlags
& 0x7) != 0x1) && /* DATA */
942 ((wFlags
& 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
944 WORD hSel
= SEL(hMem
);
945 WORD access
= SelectorAccessRights16(hSel
,0,0);
947 access
|= 2<<2; /* SEGMENT_CODE */
948 SelectorAccessRights16(hSel
,1,access
);
951 return MAKELONG( hMem
, SEL(hMem
) );
953 return MAKELONG( 0, hMem
);
956 /***********************************************************************
959 HINSTANCE16
NE_GetInstance( NE_MODULE
*pModule
)
961 if ( !pModule
->dgroup
)
962 return pModule
->self
;
966 pSeg
= NE_SEG_TABLE( pModule
) + pModule
->dgroup
- 1;
971 /***********************************************************************
974 BOOL
NE_CreateSegment( NE_MODULE
*pModule
, int segnum
)
976 SEGTABLEENTRY
*pSeg
= NE_SEG_TABLE( pModule
) + segnum
- 1;
978 unsigned char selflags
;
980 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
982 if ( segnum
< 1 || segnum
> pModule
->seg_count
)
985 if ( (pModule
->flags
& NE_FFLAGS_SELFLOAD
) && segnum
!= 1 )
986 return TRUE
; /* selfloader allocates segment itself */
988 if ( (pSeg
->flags
& NE_SEGFLAGS_ALLOCATED
) && segnum
!= pModule
->dgroup
)
989 return TRUE
; /* all but DGROUP only allocated once */
991 minsize
= pSeg
->minsize
? pSeg
->minsize
: 0x10000;
992 if ( segnum
== pModule
->ss
) minsize
+= pModule
->stack_size
;
993 if ( segnum
== pModule
->dgroup
) minsize
+= pModule
->heap_size
;
995 selflags
= (pSeg
->flags
& NE_SEGFLAGS_DATA
) ? WINE_LDT_FLAGS_DATA
: WINE_LDT_FLAGS_CODE
;
996 if (pSeg
->flags
& NE_SEGFLAGS_32BIT
) selflags
|= WINE_LDT_FLAGS_32BIT
;
997 pSeg
->hSeg
= GLOBAL_Alloc( NE_Ne2MemFlags(pSeg
->flags
), minsize
, pModule
->self
, selflags
);
998 if (!pSeg
->hSeg
) return FALSE
;
1000 pSeg
->flags
|= NE_SEGFLAGS_ALLOCATED
;
1004 /***********************************************************************
1005 * NE_CreateAllSegments
1007 BOOL
NE_CreateAllSegments( NE_MODULE
*pModule
)
1010 for ( i
= 1; i
<= pModule
->seg_count
; i
++ )
1011 if ( !NE_CreateSegment( pModule
, i
) )
1014 pModule
->dgroup_entry
= pModule
->dgroup
? pModule
->seg_table
+
1015 (pModule
->dgroup
- 1) * sizeof(SEGTABLEENTRY
) : 0;
1020 /**********************************************************************
1021 * IsSharedSelector (KERNEL.345)
1023 BOOL16 WINAPI
IsSharedSelector16( HANDLE16 selector
)
1025 /* Check whether the selector belongs to a DLL */
1026 NE_MODULE
*pModule
= NE_GetPtr( selector
);
1027 if (!pModule
) return FALSE
;
1028 return (pModule
->flags
& NE_FFLAGS_LIBMODULE
) != 0;