4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
10 #include <sys/types.h>
21 #include "selectors.h"
25 #include "stackframe.h"
31 /***********************************************************************
34 BOOL32
NE_LoadSegment( NE_MODULE
*pModule
, WORD segnum
)
36 SEGTABLEENTRY
*pSegTable
, *pSeg
;
38 WORD count
, i
, offset
;
42 struct relocation_entry_s
*rep
, *reloc_entries
;
48 int ordinal
, additive
;
51 pSegTable
= NE_SEG_TABLE( pModule
);
52 pSeg
= pSegTable
+ segnum
- 1;
53 pModuleTable
= NE_MODULE_TABLE( pModule
);
55 if (!pSeg
->filepos
) return TRUE
; /* No file image, just return */
57 fd
= MODULE_OpenFile( pModule
->self
);
58 dprintf_module( stddeb
, "Loading segment %d, selector=%04x, flags=%04x\n",
59 segnum
, pSeg
->selector
, pSeg
->flags
);
60 lseek( fd
, pSeg
->filepos
<< pModule
->alignment
, SEEK_SET
);
61 if (pSeg
->size
) size
= pSeg
->size
;
62 else if (pSeg
->minsize
) size
= pSeg
->minsize
;
64 mem
= GlobalLock16(pSeg
->selector
);
65 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
&& segnum
> 1)
67 /* Implement self loading segments */
68 SELFLOADHEADER
*selfloadheader
;
69 STACK16FRAME
*stack16Top
;
71 WORD oldselector
, newselector
;
72 THDB
*thdb
= THREAD_Current();
73 HFILE32 hf
= FILE_DupUnixHandle( fd
);
75 selfloadheader
= (SELFLOADHEADER
*)
76 PTR_SEG_OFF_TO_LIN(pSegTable
->selector
,0);
77 oldstack
= thdb
->cur_stack
;
78 oldselector
= pSeg
->selector
;
79 thdb
->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
80 0xff00 - sizeof(*stack16Top
));
81 stack16Top
= (STACK16FRAME
*)PTR_SEG_TO_LIN(thdb
->cur_stack
);
82 stack16Top
->frame32
= 0;
83 stack16Top
->ds
= stack16Top
->es
= pModule
->self_loading_sel
;
84 stack16Top
->entry_point
= 0;
85 stack16Top
->entry_ip
= 0;
86 stack16Top
->entry_cs
= 0;
90 newselector
= Callbacks
->CallLoadAppSegProc(selfloadheader
->LoadAppSeg
,
91 pModule
->self
, hf
, segnum
);
93 if (newselector
!= oldselector
) {
94 /* Self loaders like creating their own selectors;
95 * they love asking for trouble to Wine developers
97 if (segnum
== pModule
->dgroup
) {
98 memcpy(PTR_SEG_OFF_TO_LIN(oldselector
,0),
99 PTR_SEG_OFF_TO_LIN(newselector
,0),
100 pSeg
->minsize
? pSeg
->minsize
: 0x10000);
101 FreeSelector(newselector
);
102 pSeg
->selector
= oldselector
;
103 fprintf(stderr
, "A new selector was allocated for the dgroup segment\n"
104 "Old selector is %d, new one is %d", oldselector
, newselector
);
106 FreeSelector(pSeg
->selector
);
107 pSeg
->selector
= newselector
;
111 thdb
->cur_stack
= oldstack
;
113 else if (!(pSeg
->flags
& NE_SEGFLAGS_ITERATED
))
117 The following bit of code for "iterated segments" was written without
118 any documentation on the format of these segments. It seems to work,
119 but may be missing something. If you have any doco please either send
120 it to me or fix the code yourself. gfm@werple.mira.net.au
122 char* buff
= xmalloc(size
);
124 read(fd
, buff
, size
);
125 while(curr
< buff
+ size
) {
126 unsigned int rept
= *((short*) curr
)++;
127 unsigned int len
= *((short*) curr
)++;
128 for(; rept
> 0; rept
--) {
131 for(byte
= 0; byte
< len
; byte
++)
139 pSeg
->flags
|= NE_SEGFLAGS_LOADED
;
140 if (!(pSeg
->flags
& NE_SEGFLAGS_RELOC_DATA
))
141 return TRUE
; /* No relocation data, we are done */
143 read( fd
, &count
, sizeof(count
) );
144 if (!count
) return TRUE
;
146 dprintf_fixup( stddeb
, "Fixups for %*.*s, segment %d, selector %04x\n",
147 *((BYTE
*)pModule
+ pModule
->name_table
),
148 *((BYTE
*)pModule
+ pModule
->name_table
),
149 (char *)pModule
+ pModule
->name_table
+ 1,
150 segnum
, pSeg
->selector
);
152 reloc_entries
= (struct relocation_entry_s
*)xmalloc(count
* sizeof(struct relocation_entry_s
));
153 if (read( fd
, reloc_entries
, count
* sizeof(struct relocation_entry_s
)) !=
154 count
* sizeof(struct relocation_entry_s
))
156 dprintf_fixup( stddeb
, "Unable to read relocation information\n" );
161 * Go through the relocation table on entry at a time.
164 for (i
= 0; i
< count
; i
++, rep
++)
167 * Get the target address corresponding to this entry.
170 /* If additive, there is no target chain list. Instead, add source
172 additive
= rep
->relocation_type
& NE_RELFLAG_ADDITIVE
;
173 rep
->relocation_type
&= 0x3;
175 switch (rep
->relocation_type
)
177 case NE_RELTYPE_ORDINAL
:
178 module
= pModuleTable
[rep
->target1
-1];
179 ordinal
= rep
->target2
;
180 address
= MODULE_GetEntryPoint( module
, ordinal
);
183 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
185 fprintf( stderr
, "Module not found: %04x, reference %d of module %*.*s\n",
186 module
, rep
->target1
,
187 *((BYTE
*)pModule
+ pModule
->name_table
),
188 *((BYTE
*)pModule
+ pModule
->name_table
),
189 (char *)pModule
+ pModule
->name_table
+ 1 );
191 fprintf( stderr
, "Warning: no handler for %*.*s.%d, setting to 0:0\n",
192 *((BYTE
*)pTarget
+ pTarget
->name_table
),
193 *((BYTE
*)pTarget
+ pTarget
->name_table
),
194 (char *)pTarget
+ pTarget
->name_table
+ 1,
199 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
200 fprintf( stddeb
,"%d: %*.*s.%d=%04x:%04x\n", i
+ 1,
201 *((BYTE
*)pTarget
+ pTarget
->name_table
),
202 *((BYTE
*)pTarget
+ pTarget
->name_table
),
203 (char *)pTarget
+ pTarget
->name_table
+ 1,
204 ordinal
, HIWORD(address
), LOWORD(address
) );
208 case NE_RELTYPE_NAME
:
209 module
= pModuleTable
[rep
->target1
-1];
210 func_name
= (char *)pModule
+ pModule
->import_table
+ rep
->target2
;
211 memcpy( buffer
, func_name
+1, *func_name
);
212 buffer
[*func_name
] = '\0';
214 ordinal
= MODULE_GetOrdinal( module
, func_name
);
216 address
= MODULE_GetEntryPoint( module
, ordinal
);
220 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
221 fprintf( stderr
, "Warning: no handler for %.*s.%s, setting to 0:0\n",
222 *((BYTE
*)pTarget
+ pTarget
->name_table
),
223 (char *)pTarget
+ pTarget
->name_table
+ 1, func_name
);
227 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
228 fprintf( stddeb
,"%d: %.*s.%s=%04x:%04x\n", i
+ 1,
229 *((BYTE
*)pTarget
+ pTarget
->name_table
),
230 (char *)pTarget
+ pTarget
->name_table
+ 1,
231 func_name
, HIWORD(address
), LOWORD(address
) );
235 case NE_RELTYPE_INTERNAL
:
236 if ((rep
->target1
& 0xff) == 0xff)
238 address
= MODULE_GetEntryPoint( pModule
->self
, rep
->target2
);
242 address
= (FARPROC16
)PTR_SEG_OFF_TO_SEGPTR( pSegTable
[rep
->target1
-1].selector
, rep
->target2
);
245 dprintf_fixup(stddeb
,"%d: %04x:%04x\n",
246 i
+ 1, HIWORD(address
), LOWORD(address
) );
249 case NE_RELTYPE_OSFIXUP
:
250 /* Relocation type 7:
252 * These appear to be used as fixups for the Windows
253 * floating point emulator. Let's just ignore them and
254 * try to use the hardware floating point. Linux should
255 * successfully emulate the coprocessor if it doesn't
258 dprintf_fixup(stddeb
,
259 "%d: ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
260 i
+ 1, rep
->address_type
, rep
->relocation_type
,
262 dprintf_fixup(stddeb
,"TARGET %04x %04x\n",
263 rep
->target1
, rep
->target2
);
267 dprintf_fixup(stddeb
,
268 "WARNING: %d: ADDR TYPE %d, unknown TYPE %d, OFFSET %04x, ",
269 i
+ 1, rep
->address_type
, rep
->relocation_type
,
271 dprintf_fixup(stddeb
,"TARGET %04x %04x\n",
272 rep
->target1
, rep
->target2
);
277 offset
= rep
->offset
;
279 /* Apparently, high bit of address_type is sometimes set; */
280 /* we ignore it for now */
281 if (rep
->address_type
> NE_RADDR_OFFSET32
)
282 fprintf( stderr
, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
283 MODULE_GetModuleName(pModule
->self
), rep
->address_type
);
285 switch (rep
->address_type
& 0x7f)
287 case NE_RADDR_LOWBYTE
:
289 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
290 dprintf_fixup(stddeb
," %04x:%04x:%04x BYTE%s\n",
291 pSeg
->selector
, offset
, *sp
, additive
? " additive":"");
294 *(unsigned char*)sp
= (unsigned char)(((int)address
+offset
) & 0xFF);
296 *(unsigned char*)sp
= (unsigned char)((int)address
& 0xFF);
298 while (offset
!= 0xffff && !additive
);
301 case NE_RADDR_OFFSET16
:
303 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
304 dprintf_fixup(stddeb
," %04x:%04x:%04x OFFSET16%s\n",
305 pSeg
->selector
, offset
, *sp
, additive
? " additive" : "" );
307 *sp
= LOWORD(address
);
308 if (additive
) *sp
+= offset
;
310 while (offset
!= 0xffff && !additive
);
313 case NE_RADDR_POINTER32
:
315 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
316 dprintf_fixup(stddeb
," %04x:%04x:%04x POINTER32%s\n",
317 pSeg
->selector
, offset
, *sp
, additive
? " additive" : "" );
319 *sp
= LOWORD(address
);
320 if (additive
) *sp
+= offset
;
321 *(sp
+1) = HIWORD(address
);
323 while (offset
!= 0xffff && !additive
);
326 case NE_RADDR_SELECTOR
:
328 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
329 dprintf_fixup(stddeb
," %04x:%04x:%04x SELECTOR%s\n",
330 pSeg
->selector
, offset
, *sp
, additive
? " additive" : "" );
332 *sp
= HIWORD(address
);
333 /* Borland creates additive records with offset zero. Strange, but OK */
334 if(additive
&& offset
)
335 fprintf(stderr
,"Additive selector to %4.4x.Please report\n",offset
);
337 /* FIXME: Quicken 5 has a zero offset fixup. This seems to work */
338 while (offset
&& offset
!= 0xffff && !additive
);
342 dprintf_fixup(stddeb
,
343 "WARNING: %d: unknown ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
344 i
+ 1, rep
->address_type
, rep
->relocation_type
,
346 dprintf_fixup(stddeb
,
347 "TARGET %04x %04x\n", rep
->target1
, rep
->target2
);
358 /***********************************************************************
361 BOOL32
NE_LoadAllSegments( NE_MODULE
*pModule
)
365 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
368 /* Handle self loading modules */
369 SEGTABLEENTRY
* pSegTable
= (SEGTABLEENTRY
*) NE_SEG_TABLE(pModule
);
370 SELFLOADHEADER
*selfloadheader
;
371 STACK16FRAME
*stack16Top
;
372 THDB
*thdb
= THREAD_Current();
373 HMODULE16 hselfload
= GetModuleHandle16("WPROCS");
375 WORD saved_dgroup
= pSegTable
[pModule
->dgroup
- 1].selector
;
377 dprintf_module(stddeb
, "MODULE_Load: %.*s is a self-loading module!\n",
378 *((BYTE
*)pModule
+ pModule
->name_table
),
379 (char *)pModule
+ pModule
->name_table
+ 1);
380 if (!NE_LoadSegment( pModule
, 1 )) return FALSE
;
381 selfloadheader
= (SELFLOADHEADER
*)
382 PTR_SEG_OFF_TO_LIN(pSegTable
->selector
, 0);
383 selfloadheader
->EntryAddrProc
= MODULE_GetEntryPoint(hselfload
,27);
384 selfloadheader
->MyAlloc
= MODULE_GetEntryPoint(hselfload
,28);
385 selfloadheader
->SetOwner
= MODULE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
386 pModule
->self_loading_sel
= GlobalHandleToSel(GLOBAL_Alloc(GMEM_ZEROINIT
, 0xFF00, pModule
->self
, FALSE
, FALSE
, FALSE
));
387 oldstack
= thdb
->cur_stack
;
388 thdb
->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
389 0xff00 - sizeof(*stack16Top
) );
390 stack16Top
= (STACK16FRAME
*)PTR_SEG_TO_LIN(thdb
->cur_stack
);
391 stack16Top
->frame32
= 0;
393 stack16Top
->ds
= stack16Top
->es
= pModule
->self_loading_sel
;
394 stack16Top
->entry_point
= 0;
395 stack16Top
->entry_ip
= 0;
396 stack16Top
->entry_cs
= 0;
401 hf
= FILE_DupUnixHandle( MODULE_OpenFile( pModule
->self
) );
402 Callbacks
->CallBootAppProc(selfloadheader
->BootApp
, pModule
->self
, hf
);
404 /* some BootApp procs overwrite the selector of dgroup */
405 pSegTable
[pModule
->dgroup
- 1].selector
= saved_dgroup
;
406 thdb
->cur_stack
= oldstack
;
407 for (i
= 2; i
<= pModule
->seg_count
; i
++)
408 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
412 for (i
= 1; i
<= pModule
->seg_count
; i
++)
413 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
419 /***********************************************************************
422 BOOL32
NE_LoadDLLs( NE_MODULE
*pModule
)
425 WORD
*pModRef
= (WORD
*)((char *)pModule
+ pModule
->modref_table
);
426 WORD
*pDLLs
= (WORD
*)GlobalLock16( pModule
->dlls_to_init
);
428 for (i
= 0; i
< pModule
->modref_count
; i
++, pModRef
++)
431 BYTE
*pstr
= (BYTE
*)pModule
+ pModule
->import_table
+ *pModRef
;
432 memcpy( buffer
, pstr
+ 1, *pstr
);
433 strcpy( buffer
+ *pstr
, ".dll" );
434 dprintf_module( stddeb
, "Loading '%s'\n", buffer
);
435 if (!(*pModRef
= MODULE_FindModule( buffer
)))
437 /* If the DLL is not loaded yet, load it and store */
438 /* its handle in the list of DLLs to initialize. */
441 if ((hDLL
= MODULE_Load( buffer
, (LPVOID
)-1, NE_FFLAGS_IMPLICIT
)) == 2)
446 /* Try with prepending the path of the current module */
447 GetModuleFileName16( pModule
->self
, buffer
, sizeof(buffer
) );
448 if (!(p
= strrchr( buffer
, '\\' ))) p
= buffer
;
449 memcpy( p
+ 1, pstr
+ 1, *pstr
);
450 strcpy( p
+ 1 + *pstr
, ".dll" );
451 hDLL
= MODULE_Load( buffer
, (LPVOID
)-1, NE_FFLAGS_IMPLICIT
);
455 /* FIXME: cleanup what was done */
457 fprintf( stderr
, "Could not load '%s' required by '%.*s', error = %d\n",
458 buffer
, *((BYTE
*)pModule
+ pModule
->name_table
),
459 (char *)pModule
+ pModule
->name_table
+ 1, hDLL
);
462 *pModRef
= MODULE_HANDLEtoHMODULE16( hDLL
);
465 else /* Increment the reference count of the DLL */
467 NE_MODULE
*pOldDLL
= MODULE_GetPtr( *pModRef
);
468 if (pOldDLL
) pOldDLL
->count
++;
475 /***********************************************************************
478 * Fixup the exported functions prologs.
480 void NE_FixupPrologs( NE_MODULE
*pModule
)
482 SEGTABLEENTRY
*pSegTable
;
485 BYTE
*p
, *fixup_ptr
, count
;
487 pSegTable
= NE_SEG_TABLE(pModule
);
488 if (pModule
->flags
& NE_FFLAGS_SINGLEDATA
)
489 dgroup
= pSegTable
[pModule
->dgroup
-1].selector
;
491 dprintf_module( stddeb
, "MODULE_FixupPrologs(%04x)\n", pModule
->self
);
492 p
= (BYTE
*)pModule
+ pModule
->entry_table
;
495 if (p
[1] == 0) /* Unused entry */
497 p
+= 2; /* Skip it */
500 if (p
[1] == 0xfe) /* Constant entry */
502 p
+= 2 + *p
* 3; /* Skip it */
506 /* Now fixup the entries of this bundle */
512 dprintf_module( stddeb
,"Flags: %04x, sel %02x ", *p
, sel
);
513 /* According to the output generated by TDUMP, the flags mean:
514 * 0x0001 function is exported
515 * 0x0002 Single data (seems to occur only in DLLs)
517 if (sel
== 0xff) { /* moveable */
518 dprintf_module( stddeb
, "(%02x) o %04x ", p
[3], *(WORD
*)(p
+4) );
519 fixup_ptr
= (char *)GET_SEL_BASE(pSegTable
[p
[3]-1].selector
) + *(WORD
*)(p
+ 4);
521 dprintf_module( stddeb
, "offset %04x ", *(WORD
*)(p
+1) );
522 fixup_ptr
= (char *)GET_SEL_BASE(pSegTable
[sel
-1].selector
) + *(WORD
*)(p
+ 1);
524 dprintf_module( stddeb
, "Signature: %02x %02x %02x,ff %x\n",
525 fixup_ptr
[0], fixup_ptr
[1], fixup_ptr
[2],
529 /* Verify the signature */
530 if (((fixup_ptr
[0] == 0x1e && fixup_ptr
[1] == 0x58)
531 || (fixup_ptr
[0] == 0x8c && fixup_ptr
[1] == 0xd8))
532 && fixup_ptr
[2] == 0x90)
536 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
)
538 /* can this happen? */
539 fprintf( stderr
, "FixupPrologs got confused\n" );
541 else if (pModule
->flags
& NE_FFLAGS_SINGLEDATA
)
543 *fixup_ptr
= 0xb8; /* MOV AX, */
544 *(WORD
*)(fixup_ptr
+1) = dgroup
;
549 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
) {
550 fixup_ptr
[0] = 0x90; /* non-library: NOPs */
556 dprintf_fixup( stddeb
, "Unknown signature\n" );
560 dprintf_module( stddeb
,"\n");
561 p
+= (sel
== 0xff) ? 6 : 3;
567 /***********************************************************************
570 * Call the DLL initialization code
572 static BOOL32
NE_InitDLL( TDB
* pTask
, HMODULE16 hModule
)
575 SEGTABLEENTRY
*pSegTable
;
578 /* Registers at initialization must be:
580 * di library instance
581 * ds data segment if any
582 * es:si command line (always 0)
585 if (!(pModule
= MODULE_GetPtr( hModule
))) return FALSE
;
586 pSegTable
= NE_SEG_TABLE( pModule
);
588 if (!(pModule
->flags
& NE_FFLAGS_LIBMODULE
) ||
589 (pModule
->flags
& NE_FFLAGS_WIN32
)) return TRUE
; /*not a library*/
591 /* Call USER signal handler. This is necessary to install a
592 * proper loader for HICON and HCURSOR resources that this DLL
593 * may contain. InitApp() does this for task modules. */
595 if (pTask
&& pTask
->userhandler
)
597 pTask
->userhandler( hModule
, USIG_DLL_LOAD
, 0, pTask
->hInstance
,
601 if (!pModule
->cs
) return TRUE
; /* no initialization code */
603 memset( &context
, 0, sizeof(context
) );
605 if (!(pModule
->flags
& NE_FFLAGS_SINGLEDATA
))
607 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
|| pModule
->dgroup
)
610 fprintf(stderr
, "Library is not marked SINGLEDATA\n");
613 else /* DATA NONE DLL */
615 DS_reg(&context
) = 0;
616 ECX_reg(&context
) = 0;
619 else /* DATA SINGLE DLL */
621 DS_reg(&context
) = pSegTable
[pModule
->dgroup
-1].selector
;
622 ECX_reg(&context
) = pModule
->heap_size
;
625 CS_reg(&context
) = pSegTable
[pModule
->cs
-1].selector
;
626 EIP_reg(&context
) = pModule
->ip
;
627 EBP_reg(&context
) = OFFSETOF(THREAD_Current()->cur_stack
)
628 + (WORD
)&((STACK16FRAME
*)0)->bp
;
629 EDI_reg(&context
) = DS_reg(&context
) ? DS_reg(&context
) : hModule
;
632 pModule
->cs
= 0; /* Don't initialize it twice */
633 dprintf_dll( stddeb
, "Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
634 CS_reg(&context
), IP_reg(&context
), DS_reg(&context
),
635 DI_reg(&context
), CX_reg(&context
) );
636 Callbacks
->CallRegisterShortProc( &context
, 0 );
641 /***********************************************************************
644 * Recursively initialize all DLLs (according to the order in which
645 * they where loaded).
647 void NE_InitializeDLLs( HMODULE16 hModule
)
649 TDB
* pTask
= (TDB
*)GlobalLock16(GetCurrentTask());
653 if (!(pModule
= MODULE_GetPtr( hModule
))) return;
654 if (pModule
->flags
& NE_FFLAGS_WIN32
) return;
656 if (pModule
->dlls_to_init
)
658 HGLOBAL16 to_init
= pModule
->dlls_to_init
;
659 pModule
->dlls_to_init
= 0;
660 for (pDLL
= (HMODULE16
*)GlobalLock16( to_init
); *pDLL
; pDLL
++)
662 NE_InitializeDLLs( *pDLL
);
664 GlobalFree16( to_init
);
666 NE_InitDLL( pTask
, hModule
);
670 /***********************************************************************
673 * Needed for self-loading modules.
676 /* It does nothing */
677 void WINAPI
PatchCodeHandle(HANDLE16 hSel
)
679 fprintf(stderr
,"PatchCodeHandle(%04x),stub!\n",hSel
);