4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
10 #include <sys/types.h>
21 #include "selectors.h"
25 #include "stackframe.h"
30 /***********************************************************************
33 static const char *NE_GetRelocAddrName( BYTE addr_type
, int additive
)
35 switch(addr_type
& 0x7f)
37 case NE_RADDR_LOWBYTE
: return additive
? "BYTE add" : "BYTE";
38 case NE_RADDR_OFFSET16
: return additive
? "OFFSET16 add" : "OFFSET16";
39 case NE_RADDR_POINTER32
: return additive
? "POINTER32 add" : "POINTER32";
40 case NE_RADDR_SELECTOR
: return additive
? "SELECTOR add" : "SELECTOR";
41 case NE_RADDR_POINTER48
: return additive
? "POINTER48 add" : "POINTER48";
42 case NE_RADDR_OFFSET32
: return additive
? "OFFSET32 add" : "OFFSET32";
48 /***********************************************************************
51 BOOL32
NE_LoadSegment( NE_MODULE
*pModule
, WORD segnum
)
53 SEGTABLEENTRY
*pSegTable
, *pSeg
;
55 WORD count
, i
, offset
, next_offset
;
57 FARPROC16 address
= 0;
59 struct relocation_entry_s
*rep
, *reloc_entries
;
65 int ordinal
, additive
;
68 pSegTable
= NE_SEG_TABLE( pModule
);
69 pSeg
= pSegTable
+ segnum
- 1;
70 pModuleTable
= NE_MODULE_TABLE( pModule
);
72 if (!pSeg
->filepos
) return TRUE
; /* No file image, just return */
74 fd
= MODULE_OpenFile( pModule
->self
);
75 TRACE(module
, "Loading segment %d, selector=%04x, flags=%04x\n",
76 segnum
, pSeg
->selector
, pSeg
->flags
);
77 lseek( fd
, pSeg
->filepos
<< pModule
->alignment
, SEEK_SET
);
78 if (pSeg
->size
) size
= pSeg
->size
;
79 else if (pSeg
->minsize
) size
= pSeg
->minsize
;
81 mem
= GlobalLock16(pSeg
->selector
);
82 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
&& segnum
> 1)
84 /* Implement self loading segments */
85 SELFLOADHEADER
*selfloadheader
;
86 STACK16FRAME
*stack16Top
;
88 WORD oldselector
, newselector
;
89 THDB
*thdb
= THREAD_Current();
90 HFILE32 hf
= FILE_DupUnixHandle( fd
);
92 selfloadheader
= (SELFLOADHEADER
*)
93 PTR_SEG_OFF_TO_LIN(pSegTable
->selector
,0);
94 oldstack
= thdb
->cur_stack
;
95 oldselector
= pSeg
->selector
;
96 thdb
->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
97 0xff00 - sizeof(*stack16Top
));
98 stack16Top
= (STACK16FRAME
*)PTR_SEG_TO_LIN(thdb
->cur_stack
);
99 stack16Top
->frame32
= 0;
100 stack16Top
->ds
= stack16Top
->es
= pModule
->self_loading_sel
;
101 stack16Top
->entry_point
= 0;
102 stack16Top
->entry_ip
= 0;
103 stack16Top
->entry_cs
= 0;
107 newselector
= Callbacks
->CallLoadAppSegProc(selfloadheader
->LoadAppSeg
,
108 pModule
->self
, hf
, segnum
);
110 if (newselector
!= oldselector
) {
111 /* Self loaders like creating their own selectors;
112 * they love asking for trouble to Wine developers
114 if (segnum
== pModule
->dgroup
) {
115 memcpy(PTR_SEG_OFF_TO_LIN(oldselector
,0),
116 PTR_SEG_OFF_TO_LIN(newselector
,0),
117 pSeg
->minsize
? pSeg
->minsize
: 0x10000);
118 FreeSelector(newselector
);
119 pSeg
->selector
= oldselector
;
120 fprintf(stderr
, "A new selector was allocated for the dgroup segment\n"
121 "Old selector is %d, new one is %d", oldselector
, newselector
);
123 FreeSelector(pSeg
->selector
);
124 pSeg
->selector
= newselector
;
128 thdb
->cur_stack
= oldstack
;
130 else if (!(pSeg
->flags
& NE_SEGFLAGS_ITERATED
))
134 The following bit of code for "iterated segments" was written without
135 any documentation on the format of these segments. It seems to work,
136 but may be missing something. If you have any doc please either send
137 it to me or fix the code yourself. gfm@werple.mira.net.au
139 char* buff
= xmalloc(size
);
141 read(fd
, buff
, size
);
142 while(curr
< buff
+ size
) {
143 unsigned int rept
= *((short*) curr
)++;
144 unsigned int len
= *((short*) curr
)++;
145 for(; rept
> 0; rept
--) {
148 for(byte
= 0; byte
< len
; byte
++)
156 pSeg
->flags
|= NE_SEGFLAGS_LOADED
;
157 if (!(pSeg
->flags
& NE_SEGFLAGS_RELOC_DATA
))
158 return TRUE
; /* No relocation data, we are done */
160 read( fd
, &count
, sizeof(count
) );
161 if (!count
) return TRUE
;
163 TRACE(fixup
, "Fixups for %*.*s, segment %d, selector %04x\n",
164 *((BYTE
*)pModule
+ pModule
->name_table
),
165 *((BYTE
*)pModule
+ pModule
->name_table
),
166 (char *)pModule
+ pModule
->name_table
+ 1,
167 segnum
, pSeg
->selector
);
169 reloc_entries
= (struct relocation_entry_s
*)xmalloc(count
* sizeof(struct relocation_entry_s
));
170 if (read( fd
, reloc_entries
, count
* sizeof(struct relocation_entry_s
)) !=
171 count
* sizeof(struct relocation_entry_s
))
173 WARN(fixup
, "Unable to read relocation information\n" );
178 * Go through the relocation table one entry at a time.
181 for (i
= 0; i
< count
; i
++, rep
++)
184 * Get the target address corresponding to this entry.
187 /* If additive, there is no target chain list. Instead, add source
189 additive
= rep
->relocation_type
& NE_RELFLAG_ADDITIVE
;
190 rep
->relocation_type
&= 0x3;
192 switch (rep
->relocation_type
)
194 case NE_RELTYPE_ORDINAL
:
195 module
= pModuleTable
[rep
->target1
-1];
196 ordinal
= rep
->target2
;
197 address
= MODULE_GetEntryPoint( module
, ordinal
);
200 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
202 fprintf( stderr
, "Module not found: %04x, reference %d of module %*.*s\n",
203 module
, rep
->target1
,
204 *((BYTE
*)pModule
+ pModule
->name_table
),
205 *((BYTE
*)pModule
+ pModule
->name_table
),
206 (char *)pModule
+ pModule
->name_table
+ 1 );
208 fprintf( stderr
, "Warning: no handler for %.*s.%d, setting to 0:0\n",
209 *((BYTE
*)pTarget
+ pTarget
->name_table
),
210 (char *)pTarget
+ pTarget
->name_table
+ 1,
215 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
216 TRACE( fixup
, "%d: %.*s.%d=%04x:%04x %s\n", i
+ 1,
217 *((BYTE
*)pTarget
+ pTarget
->name_table
),
218 (char *)pTarget
+ pTarget
->name_table
+ 1,
219 ordinal
, HIWORD(address
), LOWORD(address
),
220 NE_GetRelocAddrName( rep
->address_type
, additive
) );
224 case NE_RELTYPE_NAME
:
225 module
= pModuleTable
[rep
->target1
-1];
226 func_name
= (char *)pModule
+ pModule
->import_table
+ rep
->target2
;
227 memcpy( buffer
, func_name
+1, *func_name
);
228 buffer
[*func_name
] = '\0';
230 ordinal
= MODULE_GetOrdinal( module
, func_name
);
232 address
= MODULE_GetEntryPoint( module
, ordinal
);
234 if (ERR_ON(fixup
) && !address
)
236 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
237 ERR(fixup
, "Warning: no handler for %.*s.%s, setting to 0:0\n",
238 *((BYTE
*)pTarget
+ pTarget
->name_table
),
239 (char *)pTarget
+ pTarget
->name_table
+ 1, func_name
);
243 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
244 TRACE( fixup
, "%d: %.*s.%s=%04x:%04x %s\n", i
+ 1,
245 *((BYTE
*)pTarget
+ pTarget
->name_table
),
246 (char *)pTarget
+ pTarget
->name_table
+ 1,
247 func_name
, HIWORD(address
), LOWORD(address
),
248 NE_GetRelocAddrName( rep
->address_type
, additive
) );
252 case NE_RELTYPE_INTERNAL
:
253 if ((rep
->target1
& 0xff) == 0xff)
255 address
= MODULE_GetEntryPoint( pModule
->self
, rep
->target2
);
259 address
= (FARPROC16
)PTR_SEG_OFF_TO_SEGPTR( pSegTable
[rep
->target1
-1].selector
, rep
->target2
);
262 TRACE( fixup
,"%d: %04x:%04x %s\n",
263 i
+ 1, HIWORD(address
), LOWORD(address
),
264 NE_GetRelocAddrName( rep
->address_type
, additive
) );
267 case NE_RELTYPE_OSFIXUP
:
268 /* Relocation type 7:
270 * These appear to be used as fixups for the Windows
271 * floating point emulator. Let's just ignore them and
272 * try to use the hardware floating point. Linux should
273 * successfully emulate the coprocessor if it doesn't
276 TRACE( fixup
, "%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
277 i
+ 1, rep
->relocation_type
, rep
->offset
,
278 rep
->target1
, rep
->target2
,
279 NE_GetRelocAddrName( rep
->address_type
, additive
) );
283 offset
= rep
->offset
;
285 /* Apparently, high bit of address_type is sometimes set; */
286 /* we ignore it for now */
287 if (rep
->address_type
> NE_RADDR_OFFSET32
)
288 ERR( fixup
, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
289 MODULE_GetModuleName(pModule
->self
), rep
->address_type
);
293 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
294 TRACE( fixup
," %04x:%04x\n", offset
, *sp
);
295 switch (rep
->address_type
& 0x7f)
297 case NE_RADDR_LOWBYTE
:
298 *(BYTE
*)sp
+= LOBYTE((int)address
);
300 case NE_RADDR_OFFSET16
:
301 *sp
+= LOWORD(address
);
303 case NE_RADDR_POINTER32
:
304 *sp
+= LOWORD(address
);
305 *(sp
+1) = HIWORD(address
);
307 case NE_RADDR_SELECTOR
:
308 /* Borland creates additive records with offset zero. Strange, but OK */
310 ERR(fixup
,"Additive selector to %04x.Please report\n",*sp
);
312 *sp
= HIWORD(address
);
317 else /* non-additive fixup */
321 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
323 TRACE( fixup
," %04x:%04x\n", offset
, *sp
);
324 switch (rep
->address_type
& 0x7f)
326 case NE_RADDR_LOWBYTE
:
327 *(BYTE
*)sp
= LOBYTE((int)address
);
329 case NE_RADDR_OFFSET16
:
330 *sp
= LOWORD(address
);
332 case NE_RADDR_POINTER32
:
333 *(FARPROC16
*)sp
= address
;
335 case NE_RADDR_SELECTOR
:
336 *sp
= SELECTOROF(address
);
341 if (next_offset
== offset
) break; /* avoid infinite loop */
342 if (next_offset
>= GlobalSize16(pSeg
->selector
)) break;
343 offset
= next_offset
;
344 } while (offset
&& (offset
!= 0xffff));
352 WARN(fixup
, "WARNING: %d: unknown ADDR TYPE %d, "
353 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
354 i
+ 1, rep
->address_type
, rep
->relocation_type
,
355 rep
->offset
, rep
->target1
, rep
->target2
);
361 /***********************************************************************
364 BOOL32
NE_LoadAllSegments( NE_MODULE
*pModule
)
368 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
371 /* Handle self loading modules */
372 SEGTABLEENTRY
* pSegTable
= (SEGTABLEENTRY
*) NE_SEG_TABLE(pModule
);
373 SELFLOADHEADER
*selfloadheader
;
374 STACK16FRAME
*stack16Top
;
375 THDB
*thdb
= THREAD_Current();
376 HMODULE16 hselfload
= GetModuleHandle16("WPROCS");
378 WORD saved_dgroup
= pSegTable
[pModule
->dgroup
- 1].selector
;
380 TRACE(module
, "%.*s is a self-loading module!\n",
381 *((BYTE
*)pModule
+ pModule
->name_table
),
382 (char *)pModule
+ pModule
->name_table
+ 1);
383 if (!NE_LoadSegment( pModule
, 1 )) return FALSE
;
384 selfloadheader
= (SELFLOADHEADER
*)
385 PTR_SEG_OFF_TO_LIN(pSegTable
->selector
, 0);
386 selfloadheader
->EntryAddrProc
= MODULE_GetEntryPoint(hselfload
,27);
387 selfloadheader
->MyAlloc
= MODULE_GetEntryPoint(hselfload
,28);
388 selfloadheader
->SetOwner
= MODULE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
389 pModule
->self_loading_sel
= GlobalHandleToSel(GLOBAL_Alloc(GMEM_ZEROINIT
, 0xFF00, pModule
->self
, FALSE
, FALSE
, FALSE
));
390 oldstack
= thdb
->cur_stack
;
391 thdb
->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
392 0xff00 - sizeof(*stack16Top
) );
393 stack16Top
= (STACK16FRAME
*)PTR_SEG_TO_LIN(thdb
->cur_stack
);
394 stack16Top
->frame32
= 0;
396 stack16Top
->ds
= stack16Top
->es
= pModule
->self_loading_sel
;
397 stack16Top
->entry_point
= 0;
398 stack16Top
->entry_ip
= 0;
399 stack16Top
->entry_cs
= 0;
404 hf
= FILE_DupUnixHandle( MODULE_OpenFile( pModule
->self
) );
405 Callbacks
->CallBootAppProc(selfloadheader
->BootApp
, pModule
->self
, hf
);
407 /* some BootApp procs overwrite the selector of dgroup */
408 pSegTable
[pModule
->dgroup
- 1].selector
= saved_dgroup
;
409 thdb
->cur_stack
= oldstack
;
410 for (i
= 2; i
<= pModule
->seg_count
; i
++)
411 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
415 for (i
= 1; i
<= pModule
->seg_count
; i
++)
416 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
422 /***********************************************************************
425 BOOL32
NE_LoadDLLs( NE_MODULE
*pModule
)
428 WORD
*pModRef
= (WORD
*)((char *)pModule
+ pModule
->modref_table
);
429 WORD
*pDLLs
= (WORD
*)GlobalLock16( pModule
->dlls_to_init
);
431 for (i
= 0; i
< pModule
->modref_count
; i
++, pModRef
++)
434 BYTE
*pstr
= (BYTE
*)pModule
+ pModule
->import_table
+ *pModRef
;
435 memcpy( buffer
, pstr
+ 1, *pstr
);
436 strcpy( buffer
+ *pstr
, ".dll" );
437 TRACE(module
, "Loading '%s'\n", buffer
);
438 if (!(*pModRef
= MODULE_FindModule( buffer
)))
440 /* If the DLL is not loaded yet, load it and store */
441 /* its handle in the list of DLLs to initialize. */
444 if ((hDLL
= MODULE_Load( buffer
, NE_FFLAGS_IMPLICIT
,
445 NULL
, NULL
, 0 )) == 2)
450 /* Try with prepending the path of the current module */
451 GetModuleFileName16( pModule
->self
, buffer
, sizeof(buffer
) );
452 if (!(p
= strrchr( buffer
, '\\' ))) p
= buffer
;
453 memcpy( p
+ 1, pstr
+ 1, *pstr
);
454 strcpy( p
+ 1 + *pstr
, ".dll" );
455 hDLL
= MODULE_Load( buffer
, NE_FFLAGS_IMPLICIT
, NULL
, NULL
, 0);
459 /* FIXME: cleanup what was done */
461 fprintf( stderr
, "Could not load '%s' required by '%.*s', error = %d\n",
462 buffer
, *((BYTE
*)pModule
+ pModule
->name_table
),
463 (char *)pModule
+ pModule
->name_table
+ 1, hDLL
);
466 *pModRef
= MODULE_HANDLEtoHMODULE16( hDLL
);
469 else /* Increment the reference count of the DLL */
471 NE_MODULE
*pOldDLL
= MODULE_GetPtr( *pModRef
);
472 if (pOldDLL
) pOldDLL
->count
++;
479 /***********************************************************************
482 * Fixup the exported functions prologs.
484 void NE_FixupPrologs( NE_MODULE
*pModule
)
486 SEGTABLEENTRY
*pSegTable
;
489 BYTE
*p
, *fixup_ptr
, count
;
490 dbg_decl_str(module
, 512);
492 pSegTable
= NE_SEG_TABLE(pModule
);
493 if (pModule
->flags
& NE_FFLAGS_SINGLEDATA
)
494 dgroup
= pSegTable
[pModule
->dgroup
-1].selector
;
496 TRACE(module
, "(%04x)\n", pModule
->self
);
497 p
= (BYTE
*)pModule
+ pModule
->entry_table
;
500 if (p
[1] == 0) /* Unused entry */
502 p
+= 2; /* Skip it */
505 if (p
[1] == 0xfe) /* Constant entry */
507 p
+= 2 + *p
* 3; /* Skip it */
511 /* Now fixup the entries of this bundle */
517 dbg_reset_str(module
);
518 dsprintf(module
,"Flags: %04x, sel %02x ", *p
, sel
);
519 /* According to the output generated by TDUMP, the flags mean:
520 * 0x0001 function is exported
521 * 0x0002 Single data (seems to occur only in DLLs)
523 if (sel
== 0xff) { /* moveable */
524 dsprintf(module
, "(%02x) o %04x", p
[3], *(WORD
*)(p
+4) );
525 fixup_ptr
= (char *)GET_SEL_BASE(pSegTable
[p
[3]-1].selector
) + *(WORD
*)(p
+ 4);
527 dsprintf(module
, "offset %04x", *(WORD
*)(p
+1) );
528 fixup_ptr
= (char *)GET_SEL_BASE(pSegTable
[sel
-1].selector
) +
531 TRACE(module
, "%s Signature: %02x %02x %02x,ff %x\n",
532 dbg_str(module
), fixup_ptr
[0], fixup_ptr
[1],
533 fixup_ptr
[2], pModule
->flags
);
536 /* Verify the signature */
537 if (((fixup_ptr
[0] == 0x1e && fixup_ptr
[1] == 0x58)
538 || (fixup_ptr
[0] == 0x8c && fixup_ptr
[1] == 0xd8))
539 && fixup_ptr
[2] == 0x90)
543 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
)
545 /* can this happen? */
546 fprintf( stderr
, "FixupPrologs got confused\n" );
548 else if (pModule
->flags
& NE_FFLAGS_SINGLEDATA
)
550 *fixup_ptr
= 0xb8; /* MOV AX, */
551 *(WORD
*)(fixup_ptr
+1) = dgroup
;
556 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
) {
557 fixup_ptr
[0] = 0x90; /* non-library: NOPs */
563 WARN(fixup
, "Unknown signature\n" );
568 p
+= (sel
== 0xff) ? 6 : 3;
574 /***********************************************************************
577 * Call the DLL initialization code
579 static BOOL32
NE_InitDLL( TDB
* pTask
, HMODULE16 hModule
)
582 SEGTABLEENTRY
*pSegTable
;
585 /* Registers at initialization must be:
587 * di library instance
588 * ds data segment if any
589 * es:si command line (always 0)
592 if (!(pModule
= MODULE_GetPtr( hModule
))) return FALSE
;
593 pSegTable
= NE_SEG_TABLE( pModule
);
595 if (!(pModule
->flags
& NE_FFLAGS_LIBMODULE
) ||
596 (pModule
->flags
& NE_FFLAGS_WIN32
)) return TRUE
; /*not a library*/
598 /* Call USER signal handler. This is necessary to install a
599 * proper loader for HICON and HCURSOR resources that this DLL
600 * may contain. InitApp() does this for task modules. */
602 if (pTask
&& pTask
->userhandler
)
604 pTask
->userhandler( hModule
, USIG_DLL_LOAD
, 0, pTask
->hInstance
,
608 if (!pModule
->cs
) return TRUE
; /* no initialization code */
610 memset( &context
, 0, sizeof(context
) );
612 if (!(pModule
->flags
& NE_FFLAGS_SINGLEDATA
))
614 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
|| pModule
->dgroup
)
617 fprintf(stderr
, "Library is not marked SINGLEDATA\n");
620 else /* DATA NONE DLL */
622 DS_reg(&context
) = 0;
623 ECX_reg(&context
) = 0;
626 else /* DATA SINGLE DLL */
628 if (pModule
->dgroup
) {
629 DS_reg(&context
) = pSegTable
[pModule
->dgroup
-1].selector
;
630 ECX_reg(&context
) = pModule
->heap_size
;
632 else /* hmm, DLL has no dgroup,
633 but why has it NE_FFLAGS_SINGLEDATA set ?
634 Buggy DLL compiler ? */
636 DS_reg(&context
) = 0;
637 ECX_reg(&context
) = 0;
641 CS_reg(&context
) = pSegTable
[pModule
->cs
-1].selector
;
642 EIP_reg(&context
) = pModule
->ip
;
643 EBP_reg(&context
) = OFFSETOF(THREAD_Current()->cur_stack
)
644 + (WORD
)&((STACK16FRAME
*)0)->bp
;
645 EDI_reg(&context
) = DS_reg(&context
) ? DS_reg(&context
) : hModule
;
648 pModule
->cs
= 0; /* Don't initialize it twice */
649 TRACE(dll
, "Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
650 CS_reg(&context
), IP_reg(&context
), DS_reg(&context
),
651 DI_reg(&context
), CX_reg(&context
) );
652 Callbacks
->CallRegisterShortProc( &context
, 0 );
657 /***********************************************************************
660 * Recursively initialize all DLLs (according to the order in which
661 * they where loaded).
663 void NE_InitializeDLLs( HMODULE16 hModule
)
665 TDB
* pTask
= (TDB
*)GlobalLock16(GetCurrentTask());
669 if (!(pModule
= MODULE_GetPtr( hModule
))) return;
670 if (pModule
->flags
& NE_FFLAGS_WIN32
) return;
672 if (pModule
->dlls_to_init
)
674 HGLOBAL16 to_init
= pModule
->dlls_to_init
;
675 pModule
->dlls_to_init
= 0;
676 for (pDLL
= (HMODULE16
*)GlobalLock16( to_init
); *pDLL
; pDLL
++)
678 NE_InitializeDLLs( *pDLL
);
680 GlobalFree16( to_init
);
682 NE_InitDLL( pTask
, hModule
);
686 /***********************************************************************
689 * Needed for self-loading modules.
692 /* It does nothing */
693 void WINAPI
PatchCodeHandle(HANDLE16 hSel
)
695 fprintf(stderr
,"PatchCodeHandle(%04x),stub!\n",hSel
);