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 BOOL32
NE_LoadSegment( NE_MODULE
*pModule
, WORD segnum
)
35 SEGTABLEENTRY
*pSegTable
, *pSeg
;
37 WORD count
, i
, offset
;
41 struct relocation_entry_s
*rep
, *reloc_entries
;
47 int ordinal
, additive
;
50 pSegTable
= NE_SEG_TABLE( pModule
);
51 pSeg
= pSegTable
+ segnum
- 1;
52 pModuleTable
= NE_MODULE_TABLE( pModule
);
54 if (!pSeg
->filepos
) return TRUE
; /* No file image, just return */
56 fd
= MODULE_OpenFile( pModule
->self
);
57 TRACE(module
, "Loading segment %d, selector=%04x, flags=%04x\n",
58 segnum
, pSeg
->selector
, pSeg
->flags
);
59 lseek( fd
, pSeg
->filepos
<< pModule
->alignment
, SEEK_SET
);
60 if (pSeg
->size
) size
= pSeg
->size
;
61 else if (pSeg
->minsize
) size
= pSeg
->minsize
;
63 mem
= GlobalLock16(pSeg
->selector
);
64 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
&& segnum
> 1)
66 /* Implement self loading segments */
67 SELFLOADHEADER
*selfloadheader
;
68 STACK16FRAME
*stack16Top
;
70 WORD oldselector
, newselector
;
71 THDB
*thdb
= THREAD_Current();
72 HFILE32 hf
= FILE_DupUnixHandle( fd
);
74 selfloadheader
= (SELFLOADHEADER
*)
75 PTR_SEG_OFF_TO_LIN(pSegTable
->selector
,0);
76 oldstack
= thdb
->cur_stack
;
77 oldselector
= pSeg
->selector
;
78 thdb
->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
79 0xff00 - sizeof(*stack16Top
));
80 stack16Top
= (STACK16FRAME
*)PTR_SEG_TO_LIN(thdb
->cur_stack
);
81 stack16Top
->frame32
= 0;
82 stack16Top
->ds
= stack16Top
->es
= pModule
->self_loading_sel
;
83 stack16Top
->entry_point
= 0;
84 stack16Top
->entry_ip
= 0;
85 stack16Top
->entry_cs
= 0;
89 newselector
= Callbacks
->CallLoadAppSegProc(selfloadheader
->LoadAppSeg
,
90 pModule
->self
, hf
, segnum
);
92 if (newselector
!= oldselector
) {
93 /* Self loaders like creating their own selectors;
94 * they love asking for trouble to Wine developers
96 if (segnum
== pModule
->dgroup
) {
97 memcpy(PTR_SEG_OFF_TO_LIN(oldselector
,0),
98 PTR_SEG_OFF_TO_LIN(newselector
,0),
99 pSeg
->minsize
? pSeg
->minsize
: 0x10000);
100 FreeSelector(newselector
);
101 pSeg
->selector
= oldselector
;
102 fprintf(stderr
, "A new selector was allocated for the dgroup segment\n"
103 "Old selector is %d, new one is %d", oldselector
, newselector
);
105 FreeSelector(pSeg
->selector
);
106 pSeg
->selector
= newselector
;
110 thdb
->cur_stack
= oldstack
;
112 else if (!(pSeg
->flags
& NE_SEGFLAGS_ITERATED
))
116 The following bit of code for "iterated segments" was written without
117 any documentation on the format of these segments. It seems to work,
118 but may be missing something. If you have any doc please either send
119 it to me or fix the code yourself. gfm@werple.mira.net.au
121 char* buff
= xmalloc(size
);
123 read(fd
, buff
, size
);
124 while(curr
< buff
+ size
) {
125 unsigned int rept
= *((short*) curr
)++;
126 unsigned int len
= *((short*) curr
)++;
127 for(; rept
> 0; rept
--) {
130 for(byte
= 0; byte
< len
; byte
++)
138 pSeg
->flags
|= NE_SEGFLAGS_LOADED
;
139 if (!(pSeg
->flags
& NE_SEGFLAGS_RELOC_DATA
))
140 return TRUE
; /* No relocation data, we are done */
142 read( fd
, &count
, sizeof(count
) );
143 if (!count
) return TRUE
;
145 TRACE(fixup
, "Fixups for %*.*s, segment %d, selector %04x\n",
146 *((BYTE
*)pModule
+ pModule
->name_table
),
147 *((BYTE
*)pModule
+ pModule
->name_table
),
148 (char *)pModule
+ pModule
->name_table
+ 1,
149 segnum
, pSeg
->selector
);
151 reloc_entries
= (struct relocation_entry_s
*)xmalloc(count
* sizeof(struct relocation_entry_s
));
152 if (read( fd
, reloc_entries
, count
* sizeof(struct relocation_entry_s
)) !=
153 count
* sizeof(struct relocation_entry_s
))
155 WARN(fixup
, "Unable to read relocation information\n" );
160 * Go through the relocation table one entry at a time.
163 for (i
= 0; i
< count
; i
++, rep
++)
166 * Get the target address corresponding to this entry.
169 /* If additive, there is no target chain list. Instead, add source
171 additive
= rep
->relocation_type
& NE_RELFLAG_ADDITIVE
;
172 rep
->relocation_type
&= 0x3;
174 switch (rep
->relocation_type
)
176 case NE_RELTYPE_ORDINAL
:
177 module
= pModuleTable
[rep
->target1
-1];
178 ordinal
= rep
->target2
;
179 address
= MODULE_GetEntryPoint( module
, ordinal
);
182 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
184 fprintf( stderr
, "Module not found: %04x, reference %d of module %*.*s\n",
185 module
, rep
->target1
,
186 *((BYTE
*)pModule
+ pModule
->name_table
),
187 *((BYTE
*)pModule
+ pModule
->name_table
),
188 (char *)pModule
+ pModule
->name_table
+ 1 );
190 fprintf( stderr
, "Warning: no handler for %*.*s.%d, setting to 0:0\n",
191 *((BYTE
*)pTarget
+ pTarget
->name_table
),
192 *((BYTE
*)pTarget
+ pTarget
->name_table
),
193 (char *)pTarget
+ pTarget
->name_table
+ 1,
198 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
199 TRACE(fixup
, "%d: %*.*s.%d=%04x:%04x\n", i
+ 1,
200 *((BYTE
*)pTarget
+ pTarget
->name_table
),
201 *((BYTE
*)pTarget
+ pTarget
->name_table
),
202 (char *)pTarget
+ pTarget
->name_table
+ 1,
203 ordinal
, HIWORD(address
), LOWORD(address
) );
207 case NE_RELTYPE_NAME
:
208 module
= pModuleTable
[rep
->target1
-1];
209 func_name
= (char *)pModule
+ pModule
->import_table
+ rep
->target2
;
210 memcpy( buffer
, func_name
+1, *func_name
);
211 buffer
[*func_name
] = '\0';
213 ordinal
= MODULE_GetOrdinal( module
, func_name
);
215 address
= MODULE_GetEntryPoint( module
, ordinal
);
217 if (ERR_ON(fixup
) && !address
)
219 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
220 ERR(fixup
, "Warning: no handler for %.*s.%s, setting to 0:0\n",
221 *((BYTE
*)pTarget
+ pTarget
->name_table
),
222 (char *)pTarget
+ pTarget
->name_table
+ 1, func_name
);
226 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
227 TRACE(fixup
, "%d: %.*s.%s=%04x:%04x\n", i
+ 1,
228 *((BYTE
*)pTarget
+ pTarget
->name_table
),
229 (char *)pTarget
+ pTarget
->name_table
+ 1,
230 func_name
, HIWORD(address
), LOWORD(address
) );
234 case NE_RELTYPE_INTERNAL
:
235 if ((rep
->target1
& 0xff) == 0xff)
237 address
= MODULE_GetEntryPoint( pModule
->self
, rep
->target2
);
241 address
= (FARPROC16
)PTR_SEG_OFF_TO_SEGPTR( pSegTable
[rep
->target1
-1].selector
, rep
->target2
);
244 TRACE(fixup
,"%d: %04x:%04x\n",
245 i
+ 1, HIWORD(address
), LOWORD(address
) );
248 case NE_RELTYPE_OSFIXUP
:
249 /* Relocation type 7:
251 * These appear to be used as fixups for the Windows
252 * floating point emulator. Let's just ignore them and
253 * try to use the hardware floating point. Linux should
254 * successfully emulate the coprocessor if it doesn't
257 TRACE(fixup
, "%d: ADDR TYPE %d, TYPE %d, OFFSET %04x, "
258 "TARGET %04x %04x\n", i
+ 1, rep
->address_type
,
259 rep
->relocation_type
, rep
->offset
, rep
->target1
, rep
->target2
);
263 WARN(fixup
, "WARNING: %d: ADDR TYPE %d, "
264 "unknown TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
265 i
+ 1, rep
->address_type
, rep
->relocation_type
,
266 rep
->offset
, rep
->target1
, rep
->target2
);
271 offset
= rep
->offset
;
273 /* Apparently, high bit of address_type is sometimes set; */
274 /* we ignore it for now */
275 if (rep
->address_type
> NE_RADDR_OFFSET32
)
276 fprintf( stderr
, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
277 MODULE_GetModuleName(pModule
->self
), rep
->address_type
);
279 switch (rep
->address_type
& 0x7f)
281 case NE_RADDR_LOWBYTE
:
283 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
284 TRACE(fixup
," %04x:%04x:%04x BYTE%s\n",
285 pSeg
->selector
, offset
, *sp
, additive
? " additive":"");
288 *(unsigned char*)sp
= (unsigned char)(((int)address
+offset
) & 0xFF);
290 *(unsigned char*)sp
= (unsigned char)((int)address
& 0xFF);
292 while (offset
&& offset
!= 0xffff && !additive
);
295 case NE_RADDR_OFFSET16
:
297 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
298 TRACE(fixup
," %04x:%04x:%04x OFFSET16%s\n",
299 pSeg
->selector
, offset
, *sp
, additive
? " additive" : "" );
301 *sp
= LOWORD(address
);
302 if (additive
) *sp
+= offset
;
304 while (offset
&& offset
!= 0xffff && !additive
);
307 case NE_RADDR_POINTER32
:
309 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
310 TRACE(fixup
," %04x:%04x:%04x POINTER32%s\n",
311 pSeg
->selector
, offset
, *sp
, additive
? " additive" : "" );
313 *sp
= LOWORD(address
);
314 if (additive
) *sp
+= offset
;
315 *(sp
+1) = HIWORD(address
);
317 while (offset
&& offset
!= 0xffff && !additive
);
320 case NE_RADDR_SELECTOR
:
322 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
323 TRACE(fixup
," %04x:%04x:%04x SELECTOR%s\n",
324 pSeg
->selector
, offset
, *sp
, additive
? " additive" : "" );
326 *sp
= HIWORD(address
);
327 /* Borland creates additive records with offset zero. Strange, but OK */
328 if(additive
&& offset
)
329 fprintf(stderr
,"Additive selector to %4.4x.Please report\n",offset
);
331 while (offset
&& offset
!= 0xffff && !additive
);
335 WARN(fixup
, "WARNING: %d: unknown ADDR TYPE %d, "
336 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
337 i
+ 1, rep
->address_type
, rep
->relocation_type
,
338 rep
->offset
, rep
->target1
, rep
->target2
);
349 /***********************************************************************
352 BOOL32
NE_LoadAllSegments( NE_MODULE
*pModule
)
356 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
359 /* Handle self loading modules */
360 SEGTABLEENTRY
* pSegTable
= (SEGTABLEENTRY
*) NE_SEG_TABLE(pModule
);
361 SELFLOADHEADER
*selfloadheader
;
362 STACK16FRAME
*stack16Top
;
363 THDB
*thdb
= THREAD_Current();
364 HMODULE16 hselfload
= GetModuleHandle16("WPROCS");
366 WORD saved_dgroup
= pSegTable
[pModule
->dgroup
- 1].selector
;
368 TRACE(module
, "%.*s is a self-loading module!\n",
369 *((BYTE
*)pModule
+ pModule
->name_table
),
370 (char *)pModule
+ pModule
->name_table
+ 1);
371 if (!NE_LoadSegment( pModule
, 1 )) return FALSE
;
372 selfloadheader
= (SELFLOADHEADER
*)
373 PTR_SEG_OFF_TO_LIN(pSegTable
->selector
, 0);
374 selfloadheader
->EntryAddrProc
= MODULE_GetEntryPoint(hselfload
,27);
375 selfloadheader
->MyAlloc
= MODULE_GetEntryPoint(hselfload
,28);
376 selfloadheader
->SetOwner
= MODULE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
377 pModule
->self_loading_sel
= GlobalHandleToSel(GLOBAL_Alloc(GMEM_ZEROINIT
, 0xFF00, pModule
->self
, FALSE
, FALSE
, FALSE
));
378 oldstack
= thdb
->cur_stack
;
379 thdb
->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
380 0xff00 - sizeof(*stack16Top
) );
381 stack16Top
= (STACK16FRAME
*)PTR_SEG_TO_LIN(thdb
->cur_stack
);
382 stack16Top
->frame32
= 0;
384 stack16Top
->ds
= stack16Top
->es
= pModule
->self_loading_sel
;
385 stack16Top
->entry_point
= 0;
386 stack16Top
->entry_ip
= 0;
387 stack16Top
->entry_cs
= 0;
392 hf
= FILE_DupUnixHandle( MODULE_OpenFile( pModule
->self
) );
393 Callbacks
->CallBootAppProc(selfloadheader
->BootApp
, pModule
->self
, hf
);
395 /* some BootApp procs overwrite the selector of dgroup */
396 pSegTable
[pModule
->dgroup
- 1].selector
= saved_dgroup
;
397 thdb
->cur_stack
= oldstack
;
398 for (i
= 2; i
<= pModule
->seg_count
; i
++)
399 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
403 for (i
= 1; i
<= pModule
->seg_count
; i
++)
404 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
410 /***********************************************************************
413 BOOL32
NE_LoadDLLs( NE_MODULE
*pModule
)
416 WORD
*pModRef
= (WORD
*)((char *)pModule
+ pModule
->modref_table
);
417 WORD
*pDLLs
= (WORD
*)GlobalLock16( pModule
->dlls_to_init
);
419 for (i
= 0; i
< pModule
->modref_count
; i
++, pModRef
++)
422 BYTE
*pstr
= (BYTE
*)pModule
+ pModule
->import_table
+ *pModRef
;
423 memcpy( buffer
, pstr
+ 1, *pstr
);
424 strcpy( buffer
+ *pstr
, ".dll" );
425 TRACE(module
, "Loading '%s'\n", buffer
);
426 if (!(*pModRef
= MODULE_FindModule( buffer
)))
428 /* If the DLL is not loaded yet, load it and store */
429 /* its handle in the list of DLLs to initialize. */
432 if ((hDLL
= MODULE_Load( buffer
, (LPVOID
)-1, NE_FFLAGS_IMPLICIT
)) == 2)
437 /* Try with prepending the path of the current module */
438 GetModuleFileName16( pModule
->self
, buffer
, sizeof(buffer
) );
439 if (!(p
= strrchr( buffer
, '\\' ))) p
= buffer
;
440 memcpy( p
+ 1, pstr
+ 1, *pstr
);
441 strcpy( p
+ 1 + *pstr
, ".dll" );
442 hDLL
= MODULE_Load( buffer
, (LPVOID
)-1, NE_FFLAGS_IMPLICIT
);
446 /* FIXME: cleanup what was done */
448 fprintf( stderr
, "Could not load '%s' required by '%.*s', error = %d\n",
449 buffer
, *((BYTE
*)pModule
+ pModule
->name_table
),
450 (char *)pModule
+ pModule
->name_table
+ 1, hDLL
);
453 *pModRef
= MODULE_HANDLEtoHMODULE16( hDLL
);
456 else /* Increment the reference count of the DLL */
458 NE_MODULE
*pOldDLL
= MODULE_GetPtr( *pModRef
);
459 if (pOldDLL
) pOldDLL
->count
++;
466 /***********************************************************************
469 * Fixup the exported functions prologs.
471 void NE_FixupPrologs( NE_MODULE
*pModule
)
473 SEGTABLEENTRY
*pSegTable
;
476 BYTE
*p
, *fixup_ptr
, count
;
477 dbg_decl_str(module
, 512);
479 pSegTable
= NE_SEG_TABLE(pModule
);
480 if (pModule
->flags
& NE_FFLAGS_SINGLEDATA
)
481 dgroup
= pSegTable
[pModule
->dgroup
-1].selector
;
483 TRACE(module
, "(%04x)\n", pModule
->self
);
484 p
= (BYTE
*)pModule
+ pModule
->entry_table
;
487 if (p
[1] == 0) /* Unused entry */
489 p
+= 2; /* Skip it */
492 if (p
[1] == 0xfe) /* Constant entry */
494 p
+= 2 + *p
* 3; /* Skip it */
498 /* Now fixup the entries of this bundle */
504 dbg_reset_str(module
);
505 dsprintf(module
,"Flags: %04x, sel %02x ", *p
, sel
);
506 /* According to the output generated by TDUMP, the flags mean:
507 * 0x0001 function is exported
508 * 0x0002 Single data (seems to occur only in DLLs)
510 if (sel
== 0xff) { /* moveable */
511 dsprintf(module
, "(%02x) o %04x", p
[3], *(WORD
*)(p
+4) );
512 fixup_ptr
= (char *)GET_SEL_BASE(pSegTable
[p
[3]-1].selector
) + *(WORD
*)(p
+ 4);
514 dsprintf(module
, "offset %04x", *(WORD
*)(p
+1) );
515 fixup_ptr
= (char *)GET_SEL_BASE(pSegTable
[sel
-1].selector
) +
518 TRACE(module
, "%s Signature: %02x %02x %02x,ff %x\n",
519 dbg_str(module
), fixup_ptr
[0], fixup_ptr
[1],
520 fixup_ptr
[2], pModule
->flags
);
523 /* Verify the signature */
524 if (((fixup_ptr
[0] == 0x1e && fixup_ptr
[1] == 0x58)
525 || (fixup_ptr
[0] == 0x8c && fixup_ptr
[1] == 0xd8))
526 && fixup_ptr
[2] == 0x90)
530 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
)
532 /* can this happen? */
533 fprintf( stderr
, "FixupPrologs got confused\n" );
535 else if (pModule
->flags
& NE_FFLAGS_SINGLEDATA
)
537 *fixup_ptr
= 0xb8; /* MOV AX, */
538 *(WORD
*)(fixup_ptr
+1) = dgroup
;
543 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
) {
544 fixup_ptr
[0] = 0x90; /* non-library: NOPs */
550 WARN(fixup
, "Unknown signature\n" );
555 p
+= (sel
== 0xff) ? 6 : 3;
561 /***********************************************************************
564 * Call the DLL initialization code
566 static BOOL32
NE_InitDLL( TDB
* pTask
, HMODULE16 hModule
)
569 SEGTABLEENTRY
*pSegTable
;
572 /* Registers at initialization must be:
574 * di library instance
575 * ds data segment if any
576 * es:si command line (always 0)
579 if (!(pModule
= MODULE_GetPtr( hModule
))) return FALSE
;
580 pSegTable
= NE_SEG_TABLE( pModule
);
582 if (!(pModule
->flags
& NE_FFLAGS_LIBMODULE
) ||
583 (pModule
->flags
& NE_FFLAGS_WIN32
)) return TRUE
; /*not a library*/
585 /* Call USER signal handler. This is necessary to install a
586 * proper loader for HICON and HCURSOR resources that this DLL
587 * may contain. InitApp() does this for task modules. */
589 if (pTask
&& pTask
->userhandler
)
591 pTask
->userhandler( hModule
, USIG_DLL_LOAD
, 0, pTask
->hInstance
,
595 if (!pModule
->cs
) return TRUE
; /* no initialization code */
597 memset( &context
, 0, sizeof(context
) );
599 if (!(pModule
->flags
& NE_FFLAGS_SINGLEDATA
))
601 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
|| pModule
->dgroup
)
604 fprintf(stderr
, "Library is not marked SINGLEDATA\n");
607 else /* DATA NONE DLL */
609 DS_reg(&context
) = 0;
610 ECX_reg(&context
) = 0;
613 else /* DATA SINGLE DLL */
615 if (pModule
->dgroup
) {
616 DS_reg(&context
) = pSegTable
[pModule
->dgroup
-1].selector
;
617 ECX_reg(&context
) = pModule
->heap_size
;
619 else /* hmm, DLL has no dgroup,
620 but why has it NE_FFLAGS_SINGLEDATA set ?
621 Buggy DLL compiler ? */
623 DS_reg(&context
) = 0;
624 ECX_reg(&context
) = 0;
628 CS_reg(&context
) = pSegTable
[pModule
->cs
-1].selector
;
629 EIP_reg(&context
) = pModule
->ip
;
630 EBP_reg(&context
) = OFFSETOF(THREAD_Current()->cur_stack
)
631 + (WORD
)&((STACK16FRAME
*)0)->bp
;
632 EDI_reg(&context
) = DS_reg(&context
) ? DS_reg(&context
) : hModule
;
635 pModule
->cs
= 0; /* Don't initialize it twice */
636 TRACE(dll
, "Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
637 CS_reg(&context
), IP_reg(&context
), DS_reg(&context
),
638 DI_reg(&context
), CX_reg(&context
) );
639 Callbacks
->CallRegisterShortProc( &context
, 0 );
644 /***********************************************************************
647 * Recursively initialize all DLLs (according to the order in which
648 * they where loaded).
650 void NE_InitializeDLLs( HMODULE16 hModule
)
652 TDB
* pTask
= (TDB
*)GlobalLock16(GetCurrentTask());
656 if (!(pModule
= MODULE_GetPtr( hModule
))) return;
657 if (pModule
->flags
& NE_FFLAGS_WIN32
) return;
659 if (pModule
->dlls_to_init
)
661 HGLOBAL16 to_init
= pModule
->dlls_to_init
;
662 pModule
->dlls_to_init
= 0;
663 for (pDLL
= (HMODULE16
*)GlobalLock16( to_init
); *pDLL
; pDLL
++)
665 NE_InitializeDLLs( *pDLL
);
667 GlobalFree16( to_init
);
669 NE_InitDLL( pTask
, hModule
);
673 /***********************************************************************
676 * Needed for self-loading modules.
679 /* It does nothing */
680 void WINAPI
PatchCodeHandle(HANDLE16 hSel
)
682 fprintf(stderr
,"PatchCodeHandle(%04x),stub!\n",hSel
);