5 * Copyright 1993 Robert J. Amstadt
6 * Copyright 1995 Alexandre Julliard
11 #include <sys/types.h>
21 #include "selectors.h"
25 #include "stackframe.h"
31 /***********************************************************************
34 BOOL32
NE_LoadSegment( HMODULE16 hModule
, WORD segnum
)
37 SEGTABLEENTRY
*pSegTable
, *pSeg
;
39 WORD count
, i
, offset
;
43 struct relocation_entry_s
*rep
, *reloc_entries
;
49 int ordinal
, additive
;
52 if (!(pModule
= MODULE_GetPtr( hModule
))) return FALSE
;
53 pSegTable
= NE_SEG_TABLE( pModule
);
54 pSeg
= pSegTable
+ segnum
- 1;
55 pModuleTable
= NE_MODULE_TABLE( pModule
);
57 if (!pSeg
->filepos
) return TRUE
; /* No file image, just return */
59 fd
= MODULE_OpenFile( hModule
);
60 dprintf_module( stddeb
, "Loading segment %d, selector=%04x\n",
61 segnum
, pSeg
->selector
);
62 lseek( fd
, pSeg
->filepos
<< pModule
->alignment
, SEEK_SET
);
63 if (pSeg
->size
) size
= pSeg
->size
;
64 else if (pSeg
->minsize
) size
= pSeg
->minsize
;
66 mem
= GlobalLock16(pSeg
->selector
);
67 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
&& segnum
> 1)
69 /* Implement self loading segments */
70 SELFLOADHEADER
*selfloadheader
;
71 STACK16FRAME
*stack16Top
;
73 WORD oldselector
, newselector
;
74 HFILE32 hf
= FILE_DupUnixHandle( fd
);
76 selfloadheader
= (SELFLOADHEADER
*)
77 PTR_SEG_OFF_TO_LIN(pSegTable
->selector
,0);
78 oldstack
= IF1632_Saved16_ss_sp
;
79 oldselector
= pSeg
->selector
;
80 IF1632_Saved16_ss_sp
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
81 0xff00 - sizeof(*stack16Top
));
82 stack16Top
= CURRENT_STACK16
;
83 stack16Top
->saved_ss_sp
= 0;
84 stack16Top
->ds
= stack16Top
->es
= pModule
->self_loading_sel
;
85 stack16Top
->entry_point
= 0;
86 stack16Top
->entry_ip
= 0;
87 stack16Top
->entry_cs
= 0;
91 newselector
= CallTo16_word_www( selfloadheader
->LoadAppSeg
,
92 hModule
, hf
, segnum
);
94 if (newselector
!= oldselector
) {
95 /* Self loaders like creating their own selectors;
96 * they love asking for trouble to Wine developers
98 if (segnum
== pModule
->dgroup
) {
99 memcpy(PTR_SEG_OFF_TO_LIN(oldselector
,0),
100 PTR_SEG_OFF_TO_LIN(newselector
,0),
101 pSeg
->minsize
? pSeg
->minsize
: 0x10000);
102 FreeSelector(newselector
);
103 pSeg
->selector
= oldselector
;
104 fprintf(stderr
, "A new selector was allocated for the dgroup segment\n"
105 "Old selector is %d, new one is %d", oldselector
, newselector
);
107 FreeSelector(pSeg
->selector
);
108 pSeg
->selector
= newselector
;
112 IF1632_Saved16_ss_sp
= oldstack
;
114 else if (!(pSeg
->flags
& NE_SEGFLAGS_ITERATED
))
118 The following bit of code for "iterated segments" was written without
119 any documentation on the format of these segments. It seems to work,
120 but may be missing something. If you have any doco please either send
121 it to me or fix the code yourself. gfm@werple.mira.net.au
123 char* buff
= xmalloc(size
);
125 read(fd
, buff
, size
);
126 while(curr
< buff
+ size
) {
127 unsigned int rept
= *((short*) curr
)++;
128 unsigned int len
= *((short*) curr
)++;
129 for(; rept
> 0; rept
--) {
132 for(byte
= 0; byte
< len
; byte
++)
140 pSeg
->flags
|= NE_SEGFLAGS_LOADED
;
141 if (!(pSeg
->flags
& NE_SEGFLAGS_RELOC_DATA
))
142 return TRUE
; /* No relocation data, we are done */
144 read( fd
, &count
, sizeof(count
) );
145 if (!count
) return TRUE
;
147 dprintf_fixup( stddeb
, "Fixups for %*.*s, segment %d, selector %04x\n",
148 *((BYTE
*)pModule
+ pModule
->name_table
),
149 *((BYTE
*)pModule
+ pModule
->name_table
),
150 (char *)pModule
+ pModule
->name_table
+ 1,
151 segnum
, pSeg
->selector
);
153 reloc_entries
= (struct relocation_entry_s
*)xmalloc(count
* sizeof(struct relocation_entry_s
));
154 if (read( fd
, reloc_entries
, count
* sizeof(struct relocation_entry_s
)) !=
155 count
* sizeof(struct relocation_entry_s
))
157 dprintf_fixup( stddeb
, "Unable to read relocation information\n" );
162 * Go through the relocation table on entry at a time.
165 for (i
= 0; i
< count
; i
++, rep
++)
168 * Get the target address corresponding to this entry.
171 /* If additive, there is no target chain list. Instead, add source
173 additive
= rep
->relocation_type
& NE_RELFLAG_ADDITIVE
;
174 rep
->relocation_type
&= 0x3;
176 switch (rep
->relocation_type
)
178 case NE_RELTYPE_ORDINAL
:
179 module
= pModuleTable
[rep
->target1
-1];
180 ordinal
= rep
->target2
;
181 address
= MODULE_GetEntryPoint( module
, ordinal
);
184 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
186 fprintf( stderr
, "Module not found: %04x, reference %d of module %*.*s\n",
187 module
, rep
->target1
,
188 *((BYTE
*)pModule
+ pModule
->name_table
),
189 *((BYTE
*)pModule
+ pModule
->name_table
),
190 (char *)pModule
+ pModule
->name_table
+ 1 );
192 fprintf( stderr
, "Warning: no handler for %*.*s.%d, setting to 0:0\n",
193 *((BYTE
*)pTarget
+ pTarget
->name_table
),
194 *((BYTE
*)pTarget
+ pTarget
->name_table
),
195 (char *)pTarget
+ pTarget
->name_table
+ 1,
200 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
201 fprintf( stddeb
,"%d: %*.*s.%d=%04x:%04x\n", i
+ 1,
202 *((BYTE
*)pTarget
+ pTarget
->name_table
),
203 *((BYTE
*)pTarget
+ pTarget
->name_table
),
204 (char *)pTarget
+ pTarget
->name_table
+ 1,
205 ordinal
, HIWORD(address
), LOWORD(address
) );
209 case NE_RELTYPE_NAME
:
210 module
= pModuleTable
[rep
->target1
-1];
211 func_name
= (char *)pModule
+ pModule
->import_table
+ rep
->target2
;
212 memcpy( buffer
, func_name
+1, *func_name
);
213 buffer
[*func_name
] = '\0';
215 ordinal
= MODULE_GetOrdinal( module
, func_name
);
217 address
= MODULE_GetEntryPoint( module
, ordinal
);
221 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
222 fprintf( stderr
, "Warning: no handler for %*.*s.%s, setting to 0:0\n",
223 *((BYTE
*)pTarget
+ pTarget
->name_table
),
224 *((BYTE
*)pTarget
+ pTarget
->name_table
),
225 (char *)pTarget
+ pTarget
->name_table
+ 1, func_name
);
229 NE_MODULE
*pTarget
= MODULE_GetPtr( module
);
230 fprintf( stddeb
,"%d: %*.*s.%s=%04x:%04x\n", i
+ 1,
231 *((BYTE
*)pTarget
+ pTarget
->name_table
),
232 *((BYTE
*)pTarget
+ pTarget
->name_table
),
233 (char *)pTarget
+ pTarget
->name_table
+ 1,
234 func_name
, HIWORD(address
), LOWORD(address
) );
238 case NE_RELTYPE_INTERNAL
:
239 if ((rep
->target1
& 0xff) == 0xff)
241 address
= MODULE_GetEntryPoint( hModule
, rep
->target2
);
245 address
= (FARPROC16
)PTR_SEG_OFF_TO_SEGPTR( pSegTable
[rep
->target1
-1].selector
, rep
->target2
);
248 dprintf_fixup(stddeb
,"%d: %04x:%04x\n",
249 i
+ 1, HIWORD(address
), LOWORD(address
) );
252 case NE_RELTYPE_OSFIXUP
:
253 /* Relocation type 7:
255 * These appear to be used as fixups for the Windows
256 * floating point emulator. Let's just ignore them and
257 * try to use the hardware floating point. Linux should
258 * successfully emulate the coprocessor if it doesn't
261 dprintf_fixup(stddeb
,
262 "%d: ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
263 i
+ 1, rep
->address_type
, rep
->relocation_type
,
265 dprintf_fixup(stddeb
,"TARGET %04x %04x\n",
266 rep
->target1
, rep
->target2
);
270 dprintf_fixup(stddeb
,
271 "WARNING: %d: ADDR TYPE %d, unknown TYPE %d, OFFSET %04x, ",
272 i
+ 1, rep
->address_type
, rep
->relocation_type
,
274 dprintf_fixup(stddeb
,"TARGET %04x %04x\n",
275 rep
->target1
, rep
->target2
);
280 offset
= rep
->offset
;
282 /* Apparently, high bit of address_type is sometimes set; */
283 /* we ignore it for now */
284 if (rep
->address_type
> NE_RADDR_OFFSET32
)
285 fprintf( stderr
, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
286 MODULE_GetModuleName(hModule
), rep
->address_type
);
288 switch (rep
->address_type
& 0x7f)
290 case NE_RADDR_LOWBYTE
:
292 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
293 dprintf_fixup(stddeb
," %04x:%04x:%04x BYTE%s\n",
294 pSeg
->selector
, offset
, *sp
, additive
? " additive":"");
297 *(unsigned char*)sp
= (unsigned char)(((int)address
+offset
) & 0xFF);
299 *(unsigned char*)sp
= (unsigned char)((int)address
& 0xFF);
301 while (offset
!= 0xffff && !additive
);
304 case NE_RADDR_OFFSET16
:
306 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
307 dprintf_fixup(stddeb
," %04x:%04x:%04x OFFSET16%s\n",
308 pSeg
->selector
, offset
, *sp
, additive
? " additive" : "" );
310 *sp
= LOWORD(address
);
311 if (additive
) *sp
+= offset
;
313 while (offset
!= 0xffff && !additive
);
316 case NE_RADDR_POINTER32
:
318 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
319 dprintf_fixup(stddeb
," %04x:%04x:%04x POINTER32%s\n",
320 pSeg
->selector
, offset
, *sp
, additive
? " additive" : "" );
322 *sp
= LOWORD(address
);
323 if (additive
) *sp
+= offset
;
324 *(sp
+1) = HIWORD(address
);
326 while (offset
!= 0xffff && !additive
);
329 case NE_RADDR_SELECTOR
:
331 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
332 dprintf_fixup(stddeb
," %04x:%04x:%04x SELECTOR%s\n",
333 pSeg
->selector
, offset
, *sp
, additive
? " additive" : "" );
335 *sp
= HIWORD(address
);
336 /* Borland creates additive records with offset zero. Strange, but OK */
337 if(additive
&& offset
)
338 fprintf(stderr
,"Additive selector to %4.4x.Please report\n",offset
);
340 /* FIXME: Quicken 5 has a zero offset fixup. This seems to work */
341 while (offset
&& offset
!= 0xffff && !additive
);
345 dprintf_fixup(stddeb
,
346 "WARNING: %d: unknown ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
347 i
+ 1, rep
->address_type
, rep
->relocation_type
,
349 dprintf_fixup(stddeb
,
350 "TARGET %04x %04x\n", rep
->target1
, rep
->target2
);
361 /***********************************************************************
364 * Fixup the exported functions prologs.
366 void NE_FixupPrologs( NE_MODULE
*pModule
)
368 SEGTABLEENTRY
*pSegTable
;
371 BYTE
*p
, *fixup_ptr
, count
;
373 pSegTable
= NE_SEG_TABLE(pModule
);
374 if (pModule
->flags
& NE_FFLAGS_SINGLEDATA
)
375 dgroup
= pSegTable
[pModule
->dgroup
-1].selector
;
377 dprintf_module( stddeb
, "MODULE_FixupPrologs(%04x)\n", pModule
->self
);
378 p
= (BYTE
*)pModule
+ pModule
->entry_table
;
381 if (p
[1] == 0) /* Unused entry */
383 p
+= 2; /* Skip it */
386 if (p
[1] == 0xfe) /* Constant entry */
388 p
+= 2 + *p
* 3; /* Skip it */
392 /* Now fixup the entries of this bundle */
398 dprintf_module( stddeb
,"Flags: %04x, sel %02x ", *p
, sel
);
399 /* According to the output generated by TDUMP, the flags mean:
400 * 0x0001 function is exported
401 * 0x0002 Single data (seems to occur only in DLLs)
403 if (sel
== 0xff) { /* moveable */
404 dprintf_module( stddeb
, "(%02x) o %04x ", p
[3], *(WORD
*)(p
+4) );
405 fixup_ptr
= (char *)GET_SEL_BASE(pSegTable
[p
[3]-1].selector
) + *(WORD
*)(p
+ 4);
407 dprintf_module( stddeb
, "offset %04x ", *(WORD
*)(p
+1) );
408 fixup_ptr
= (char *)GET_SEL_BASE(pSegTable
[sel
-1].selector
) + *(WORD
*)(p
+ 1);
410 dprintf_module( stddeb
, "Signature: %02x %02x %02x,ff %x\n",
411 fixup_ptr
[0], fixup_ptr
[1], fixup_ptr
[2],
415 /* Verify the signature */
416 if (((fixup_ptr
[0] == 0x1e && fixup_ptr
[1] == 0x58)
417 || (fixup_ptr
[0] == 0x8c && fixup_ptr
[1] == 0xd8))
418 && fixup_ptr
[2] == 0x90)
422 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
)
424 /* can this happen? */
425 fprintf( stderr
, "FixupPrologs got confused\n" );
427 else if (pModule
->flags
& NE_FFLAGS_SINGLEDATA
)
429 *fixup_ptr
= 0xb8; /* MOV AX, */
430 *(WORD
*)(fixup_ptr
+1) = dgroup
;
435 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
) {
436 fixup_ptr
[0] = 0x90; /* non-library: NOPs */
442 dprintf_fixup( stddeb
, "Unknown signature\n" );
446 dprintf_module( stddeb
,"\n");
447 p
+= (sel
== 0xff) ? 6 : 3;
453 /***********************************************************************
456 * Call the DLL initialization code
458 static BOOL32
NE_InitDLL( TDB
* pTask
, HMODULE16 hModule
)
461 SEGTABLEENTRY
*pSegTable
;
464 /* Registers at initialization must be:
466 * di library instance
467 * ds data segment if any
468 * es:si command line (always 0)
471 if (!(pModule
= MODULE_GetPtr( hModule
))) return FALSE
;
472 pSegTable
= NE_SEG_TABLE( pModule
);
474 if (!(pModule
->flags
& NE_FFLAGS_LIBMODULE
) ||
475 (pModule
->flags
& NE_FFLAGS_WIN32
)) return TRUE
; /*not a library*/
477 /* Call USER signal handler. This is necessary to install a
478 * proper loader for HICON and HCURSOR resources that this DLL
479 * may contain. InitApp() does this for task modules. */
481 if (pTask
&& pTask
->userhandler
)
483 pTask
->userhandler( hModule
, USIG_DLL_LOAD
, 0, pTask
->hInstance
,
487 if (!pModule
->cs
) return TRUE
; /* no initialization code */
489 memset( &context
, 0, sizeof(context
) );
491 if (!(pModule
->flags
& NE_FFLAGS_SINGLEDATA
))
493 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
|| pModule
->dgroup
)
496 fprintf(stderr
, "Library is not marked SINGLEDATA\n");
499 else /* DATA NONE DLL */
501 DS_reg(&context
) = 0;
502 ECX_reg(&context
) = 0;
505 else /* DATA SINGLE DLL */
507 DS_reg(&context
) = pSegTable
[pModule
->dgroup
-1].selector
;
508 ECX_reg(&context
) = pModule
->heap_size
;
511 CS_reg(&context
) = pSegTable
[pModule
->cs
-1].selector
;
512 EIP_reg(&context
) = pModule
->ip
;
513 EBP_reg(&context
) = OFFSETOF(IF1632_Saved16_ss_sp
)
514 + (WORD
)&((STACK16FRAME
*)0)->bp
;
515 EDI_reg(&context
) = DS_reg(&context
) ? DS_reg(&context
) : hModule
;
518 pModule
->cs
= 0; /* Don't initialize it twice */
519 dprintf_dll( stddeb
, "Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
520 CS_reg(&context
), IP_reg(&context
), DS_reg(&context
),
521 DI_reg(&context
), CX_reg(&context
) );
522 CallTo16_regs_( &context
, 0 );
527 /***********************************************************************
530 * Recursively initialize all DLLs (according to the order in which
531 * they where loaded).
533 void NE_InitializeDLLs( HMODULE16 hModule
)
535 TDB
* pTask
= (TDB
*)GlobalLock16(GetCurrentTask());
539 if (!(pModule
= MODULE_GetPtr( hModule
))) return;
540 if (pModule
->flags
& NE_FFLAGS_WIN32
)
542 /* PE_InitializeDLLs(hModule); */
546 if (pModule
->dlls_to_init
)
548 HGLOBAL16 to_init
= pModule
->dlls_to_init
;
549 pModule
->dlls_to_init
= 0;
550 for (pDLL
= (HMODULE16
*)GlobalLock16( to_init
); *pDLL
; pDLL
++)
552 NE_InitializeDLLs( *pDLL
);
554 GlobalFree16( to_init
);
556 NE_InitDLL( pTask
, hModule
);
560 /***********************************************************************
563 * Needed for self-loading modules.
566 /* It does nothing */
567 void WINAPI
PatchCodeHandle(HANDLE16 hSel
)