4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
11 #include <sys/types.h>
22 #include "selectors.h"
26 #include "stackframe.h"
31 /***********************************************************************
34 static const char *NE_GetRelocAddrName( BYTE addr_type
, int additive
)
36 switch(addr_type
& 0x7f)
38 case NE_RADDR_LOWBYTE
: return additive
? "BYTE add" : "BYTE";
39 case NE_RADDR_OFFSET16
: return additive
? "OFFSET16 add" : "OFFSET16";
40 case NE_RADDR_POINTER32
: return additive
? "POINTER32 add" : "POINTER32";
41 case NE_RADDR_SELECTOR
: return additive
? "SELECTOR add" : "SELECTOR";
42 case NE_RADDR_POINTER48
: return additive
? "POINTER48 add" : "POINTER48";
43 case NE_RADDR_OFFSET32
: return additive
? "OFFSET32 add" : "OFFSET32";
49 /***********************************************************************
52 BOOL32
NE_LoadSegment( NE_MODULE
*pModule
, WORD segnum
)
54 SEGTABLEENTRY
*pSegTable
, *pSeg
;
56 WORD count
, i
, offset
, next_offset
;
58 FARPROC16 address
= 0;
60 struct relocation_entry_s
*rep
, *reloc_entries
;
66 int ordinal
, additive
;
69 pSegTable
= NE_SEG_TABLE( pModule
);
70 pSeg
= pSegTable
+ segnum
- 1;
71 pModuleTable
= NE_MODULE_TABLE( pModule
);
73 if (!pSeg
->filepos
) return TRUE
; /* No file image, just return */
75 fd
= MODULE_OpenFile( pModule
->self
);
76 TRACE(module
, "Loading segment %d, selector=%04x, flags=%04x\n",
77 segnum
, pSeg
->selector
, pSeg
->flags
);
78 lseek( fd
, pSeg
->filepos
<< pModule
->alignment
, SEEK_SET
);
79 if (pSeg
->size
) size
= pSeg
->size
;
80 else if (pSeg
->minsize
) size
= pSeg
->minsize
;
82 mem
= GlobalLock16(pSeg
->selector
);
83 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
&& segnum
> 1)
85 /* Implement self loading segments */
86 SELFLOADHEADER
*selfloadheader
;
87 STACK16FRAME
*stack16Top
;
89 WORD oldselector
, newselector
;
90 THDB
*thdb
= THREAD_Current();
91 HFILE32 hf
= FILE_DupUnixHandle( fd
);
93 selfloadheader
= (SELFLOADHEADER
*)
94 PTR_SEG_OFF_TO_LIN(pSegTable
->selector
,0);
95 oldstack
= thdb
->cur_stack
;
96 oldselector
= pSeg
->selector
;
97 thdb
->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
98 0xff00 - sizeof(*stack16Top
));
99 stack16Top
= (STACK16FRAME
*)PTR_SEG_TO_LIN(thdb
->cur_stack
);
100 stack16Top
->frame32
= 0;
101 stack16Top
->ds
= stack16Top
->es
= pModule
->self_loading_sel
;
102 stack16Top
->entry_point
= 0;
103 stack16Top
->entry_ip
= 0;
104 stack16Top
->entry_cs
= 0;
108 newselector
= Callbacks
->CallLoadAppSegProc(selfloadheader
->LoadAppSeg
,
109 pModule
->self
, hf
, segnum
);
111 if (newselector
!= oldselector
) {
112 /* Self loaders like creating their own selectors;
113 * they love asking for trouble to Wine developers
115 if (segnum
== pModule
->dgroup
) {
116 memcpy(PTR_SEG_OFF_TO_LIN(oldselector
,0),
117 PTR_SEG_OFF_TO_LIN(newselector
,0),
118 pSeg
->minsize
? pSeg
->minsize
: 0x10000);
119 FreeSelector(newselector
);
120 pSeg
->selector
= oldselector
;
121 fprintf(stderr
, "A new selector was allocated for the dgroup segment\n"
122 "Old selector is %d, new one is %d", oldselector
, newselector
);
124 FreeSelector(pSeg
->selector
);
125 pSeg
->selector
= newselector
;
129 thdb
->cur_stack
= oldstack
;
131 else if (!(pSeg
->flags
& NE_SEGFLAGS_ITERATED
))
135 The following bit of code for "iterated segments" was written without
136 any documentation on the format of these segments. It seems to work,
137 but may be missing something. If you have any doc please either send
138 it to me or fix the code yourself. gfm@werple.mira.net.au
140 char* buff
= xmalloc(size
);
142 read(fd
, buff
, size
);
143 while(curr
< buff
+ size
) {
144 unsigned int rept
= *((short*) curr
)++;
145 unsigned int len
= *((short*) curr
)++;
146 for(; rept
> 0; rept
--) {
149 for(byte
= 0; byte
< len
; byte
++)
157 pSeg
->flags
|= NE_SEGFLAGS_LOADED
;
158 if (!(pSeg
->flags
& NE_SEGFLAGS_RELOC_DATA
))
159 return TRUE
; /* No relocation data, we are done */
161 read( fd
, &count
, sizeof(count
) );
162 if (!count
) return TRUE
;
164 TRACE(fixup
, "Fixups for %.*s, segment %d, selector %04x\n",
165 *((BYTE
*)pModule
+ pModule
->name_table
),
166 (char *)pModule
+ pModule
->name_table
+ 1,
167 segnum
, pSeg
->selector
);
168 TRACE(segment
, "Fixups for %.*s, segment %d, selector %04x\n",
169 *((BYTE
*)pModule
+ pModule
->name_table
),
170 (char *)pModule
+ pModule
->name_table
+ 1,
171 segnum
, pSeg
->selector
);
173 reloc_entries
= (struct relocation_entry_s
*)xmalloc(count
* sizeof(struct relocation_entry_s
));
174 if (read( fd
, reloc_entries
, count
* sizeof(struct relocation_entry_s
)) !=
175 count
* sizeof(struct relocation_entry_s
))
177 WARN(fixup
, "Unable to read relocation information\n" );
182 * Go through the relocation table one entry at a time.
185 for (i
= 0; i
< count
; i
++, rep
++)
188 * Get the target address corresponding to this entry.
191 /* If additive, there is no target chain list. Instead, add source
193 additive
= rep
->relocation_type
& NE_RELFLAG_ADDITIVE
;
194 rep
->relocation_type
&= 0x3;
196 switch (rep
->relocation_type
)
198 case NE_RELTYPE_ORDINAL
:
199 module
= pModuleTable
[rep
->target1
-1];
200 ordinal
= rep
->target2
;
201 address
= NE_GetEntryPoint( module
, ordinal
);
204 NE_MODULE
*pTarget
= MODULE_GetPtr16( module
);
206 fprintf( stderr
, "Module not found: %04x, reference %d of module %*.*s\n",
207 module
, rep
->target1
,
208 *((BYTE
*)pModule
+ pModule
->name_table
),
209 *((BYTE
*)pModule
+ pModule
->name_table
),
210 (char *)pModule
+ pModule
->name_table
+ 1 );
212 fprintf( stderr
, "Warning: no handler for %.*s.%d, setting to 0:0\n",
213 *((BYTE
*)pTarget
+ pTarget
->name_table
),
214 (char *)pTarget
+ pTarget
->name_table
+ 1,
219 NE_MODULE
*pTarget
= MODULE_GetPtr16( module
);
220 TRACE( fixup
, "%d: %.*s.%d=%04x:%04x %s\n", i
+ 1,
221 *((BYTE
*)pTarget
+ pTarget
->name_table
),
222 (char *)pTarget
+ pTarget
->name_table
+ 1,
223 ordinal
, HIWORD(address
), LOWORD(address
),
224 NE_GetRelocAddrName( rep
->address_type
, additive
) );
228 case NE_RELTYPE_NAME
:
229 module
= pModuleTable
[rep
->target1
-1];
230 func_name
= (char *)pModule
+ pModule
->import_table
+ rep
->target2
;
231 memcpy( buffer
, func_name
+1, *func_name
);
232 buffer
[*func_name
] = '\0';
234 ordinal
= NE_GetOrdinal( module
, func_name
);
235 address
= NE_GetEntryPoint( module
, ordinal
);
237 if (ERR_ON(fixup
) && !address
)
239 NE_MODULE
*pTarget
= MODULE_GetPtr16( module
);
240 ERR(fixup
, "Warning: no handler for %.*s.%s, setting to 0:0\n",
241 *((BYTE
*)pTarget
+ pTarget
->name_table
),
242 (char *)pTarget
+ pTarget
->name_table
+ 1, func_name
);
246 NE_MODULE
*pTarget
= MODULE_GetPtr16( module
);
247 TRACE( fixup
, "%d: %.*s.%s=%04x:%04x %s\n", i
+ 1,
248 *((BYTE
*)pTarget
+ pTarget
->name_table
),
249 (char *)pTarget
+ pTarget
->name_table
+ 1,
250 func_name
, HIWORD(address
), LOWORD(address
),
251 NE_GetRelocAddrName( rep
->address_type
, additive
) );
255 case NE_RELTYPE_INTERNAL
:
256 if ((rep
->target1
& 0xff) == 0xff)
258 address
= NE_GetEntryPoint( pModule
->self
, rep
->target2
);
262 address
= (FARPROC16
)PTR_SEG_OFF_TO_SEGPTR( pSegTable
[rep
->target1
-1].selector
, rep
->target2
);
265 TRACE( fixup
,"%d: %04x:%04x %s\n",
266 i
+ 1, HIWORD(address
), LOWORD(address
),
267 NE_GetRelocAddrName( rep
->address_type
, additive
) );
270 case NE_RELTYPE_OSFIXUP
:
271 /* Relocation type 7:
273 * These appear to be used as fixups for the Windows
274 * floating point emulator. Let's just ignore them and
275 * try to use the hardware floating point. Linux should
276 * successfully emulate the coprocessor if it doesn't
279 TRACE( fixup
, "%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
280 i
+ 1, rep
->relocation_type
, rep
->offset
,
281 rep
->target1
, rep
->target2
,
282 NE_GetRelocAddrName( rep
->address_type
, additive
) );
286 offset
= rep
->offset
;
288 /* Apparently, high bit of address_type is sometimes set; */
289 /* we ignore it for now */
290 if (rep
->address_type
> NE_RADDR_OFFSET32
)
291 ERR( fixup
, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
292 MODULE_GetModuleName(pModule
->self
), rep
->address_type
);
296 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
297 TRACE( fixup
," %04x:%04x\n", offset
, *sp
);
298 switch (rep
->address_type
& 0x7f)
300 case NE_RADDR_LOWBYTE
:
301 *(BYTE
*)sp
+= LOBYTE((int)address
);
303 case NE_RADDR_OFFSET16
:
304 *sp
+= LOWORD(address
);
306 case NE_RADDR_POINTER32
:
307 *sp
+= LOWORD(address
);
308 *(sp
+1) = HIWORD(address
);
310 case NE_RADDR_SELECTOR
:
311 /* Borland creates additive records with offset zero. Strange, but OK */
313 ERR(fixup
,"Additive selector to %04x.Please report\n",*sp
);
315 *sp
= HIWORD(address
);
321 else /* non-additive fixup */
325 sp
= PTR_SEG_OFF_TO_LIN( pSeg
->selector
, offset
);
327 TRACE( fixup
," %04x:%04x\n", offset
, *sp
);
328 switch (rep
->address_type
& 0x7f)
330 case NE_RADDR_LOWBYTE
:
331 *(BYTE
*)sp
= LOBYTE((int)address
);
333 case NE_RADDR_OFFSET16
:
334 *sp
= LOWORD(address
);
336 case NE_RADDR_POINTER32
:
337 *(FARPROC16
*)sp
= address
;
339 case NE_RADDR_SELECTOR
:
340 *sp
= SELECTOROF(address
);
345 if (next_offset
== offset
) break; /* avoid infinite loop */
346 if (next_offset
>= GlobalSize16(pSeg
->selector
)) break;
347 offset
= next_offset
;
348 } while (offset
&& (offset
!= 0xffff));
356 WARN(fixup
, "WARNING: %d: unknown ADDR TYPE %d, "
357 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
358 i
+ 1, rep
->address_type
, rep
->relocation_type
,
359 rep
->offset
, rep
->target1
, rep
->target2
);
365 /***********************************************************************
368 BOOL32
NE_LoadAllSegments( NE_MODULE
*pModule
)
372 if (pModule
->flags
& NE_FFLAGS_SELFLOAD
)
375 /* Handle self loading modules */
376 SEGTABLEENTRY
* pSegTable
= (SEGTABLEENTRY
*) NE_SEG_TABLE(pModule
);
377 SELFLOADHEADER
*selfloadheader
;
378 STACK16FRAME
*stack16Top
;
379 THDB
*thdb
= THREAD_Current();
380 HMODULE16 hselfload
= GetModuleHandle16("WPROCS");
382 WORD saved_dgroup
= pSegTable
[pModule
->dgroup
- 1].selector
;
384 TRACE(module
, "%.*s is a self-loading module!\n",
385 *((BYTE
*)pModule
+ pModule
->name_table
),
386 (char *)pModule
+ pModule
->name_table
+ 1);
387 if (!NE_LoadSegment( pModule
, 1 )) return FALSE
;
388 selfloadheader
= (SELFLOADHEADER
*)
389 PTR_SEG_OFF_TO_LIN(pSegTable
->selector
, 0);
390 selfloadheader
->EntryAddrProc
= NE_GetEntryPoint(hselfload
,27);
391 selfloadheader
->MyAlloc
= NE_GetEntryPoint(hselfload
,28);
392 selfloadheader
->SetOwner
= NE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
393 pModule
->self_loading_sel
= GlobalHandleToSel(GLOBAL_Alloc(GMEM_ZEROINIT
, 0xFF00, pModule
->self
, FALSE
, FALSE
, FALSE
));
394 oldstack
= thdb
->cur_stack
;
395 thdb
->cur_stack
= PTR_SEG_OFF_TO_SEGPTR(pModule
->self_loading_sel
,
396 0xff00 - sizeof(*stack16Top
) );
397 stack16Top
= (STACK16FRAME
*)PTR_SEG_TO_LIN(thdb
->cur_stack
);
398 stack16Top
->frame32
= 0;
400 stack16Top
->ds
= stack16Top
->es
= pModule
->self_loading_sel
;
401 stack16Top
->entry_point
= 0;
402 stack16Top
->entry_ip
= 0;
403 stack16Top
->entry_cs
= 0;
408 hf
= FILE_DupUnixHandle( MODULE_OpenFile( pModule
->self
) );
409 Callbacks
->CallBootAppProc(selfloadheader
->BootApp
, pModule
->self
, hf
);
411 /* some BootApp procs overwrite the selector of dgroup */
412 pSegTable
[pModule
->dgroup
- 1].selector
= saved_dgroup
;
413 thdb
->cur_stack
= oldstack
;
414 for (i
= 2; i
<= pModule
->seg_count
; i
++)
415 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
419 for (i
= 1; i
<= pModule
->seg_count
; i
++)
420 if (!NE_LoadSegment( pModule
, i
)) return FALSE
;
426 /***********************************************************************
429 * Fixup the exported functions prologs.
431 void NE_FixupPrologs( NE_MODULE
*pModule
)
433 SEGTABLEENTRY
*pSegTable
;
436 BYTE
*p
, *fixup_ptr
, count
;
437 dbg_decl_str(module
, 512);
439 pSegTable
= NE_SEG_TABLE(pModule
);
440 if (pModule
->flags
& NE_FFLAGS_SINGLEDATA
)
441 dgroup
= pSegTable
[pModule
->dgroup
-1].selector
;
443 TRACE(module
, "(%04x)\n", pModule
->self
);
444 p
= (BYTE
*)pModule
+ pModule
->entry_table
;
447 if (p
[1] == 0) /* Unused entry */
449 p
+= 2; /* Skip it */
452 if (p
[1] == 0xfe) /* Constant entry */
454 p
+= 2 + *p
* 3; /* Skip it */
458 /* Now fixup the entries of this bundle */
464 dbg_reset_str(module
);
465 dsprintf(module
,"Flags: %04x, sel %02x ", *p
, sel
);
466 /* According to the output generated by TDUMP, the flags mean:
467 * 0x0001 function is exported
468 * 0x0002 Single data (seems to occur only in DLLs)
470 if (sel
== 0xff) { /* moveable */
471 dsprintf(module
, "(%02x) o %04x", p
[3], *(WORD
*)(p
+4) );
472 fixup_ptr
= (char *)GET_SEL_BASE(pSegTable
[p
[3]-1].selector
) + *(WORD
*)(p
+ 4);
474 dsprintf(module
, "offset %04x", *(WORD
*)(p
+1) );
475 fixup_ptr
= (char *)GET_SEL_BASE(pSegTable
[sel
-1].selector
) +
478 TRACE(module
, "%s Signature: %02x %02x %02x,ff %x\n",
479 dbg_str(module
), fixup_ptr
[0], fixup_ptr
[1],
480 fixup_ptr
[2], pModule
->flags
);
483 /* Verify the signature */
484 if (((fixup_ptr
[0] == 0x1e && fixup_ptr
[1] == 0x58)
485 || (fixup_ptr
[0] == 0x8c && fixup_ptr
[1] == 0xd8))
486 && fixup_ptr
[2] == 0x90)
490 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
)
492 /* can this happen? */
493 fprintf( stderr
, "FixupPrologs got confused\n" );
495 else if (pModule
->flags
& NE_FFLAGS_SINGLEDATA
)
497 *fixup_ptr
= 0xb8; /* MOV AX, */
498 *(WORD
*)(fixup_ptr
+1) = dgroup
;
503 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
) {
504 fixup_ptr
[0] = 0x90; /* non-library: NOPs */
510 WARN(fixup
, "Unknown signature\n" );
515 p
+= (sel
== 0xff) ? 6 : 3;
521 /***********************************************************************
524 * Call the DLL initialization code
526 static BOOL32
NE_InitDLL( TDB
* pTask
, HMODULE16 hModule
)
529 SEGTABLEENTRY
*pSegTable
;
532 /* Registers at initialization must be:
534 * di library instance
535 * ds data segment if any
536 * es:si command line (always 0)
539 if (!(pModule
= MODULE_GetPtr16( hModule
))) return FALSE
;
540 pSegTable
= NE_SEG_TABLE( pModule
);
542 if (!(pModule
->flags
& NE_FFLAGS_LIBMODULE
) ||
543 (pModule
->flags
& NE_FFLAGS_WIN32
)) return TRUE
; /*not a library*/
545 /* Call USER signal handler. This is necessary to install a
546 * proper loader for HICON and HCURSOR resources that this DLL
547 * may contain. InitApp() does this for task modules. */
549 if (pTask
&& pTask
->userhandler
)
551 pTask
->userhandler( hModule
, USIG_DLL_LOAD
, 0, pTask
->hInstance
,
555 if (!pModule
->cs
) return TRUE
; /* no initialization code */
557 memset( &context
, 0, sizeof(context
) );
559 if (!(pModule
->flags
& NE_FFLAGS_SINGLEDATA
))
561 if (pModule
->flags
& NE_FFLAGS_MULTIPLEDATA
|| pModule
->dgroup
)
564 fprintf(stderr
, "Library is not marked SINGLEDATA\n");
567 else /* DATA NONE DLL */
569 DS_reg(&context
) = 0;
570 ECX_reg(&context
) = 0;
573 else /* DATA SINGLE DLL */
575 if (pModule
->dgroup
) {
576 DS_reg(&context
) = pSegTable
[pModule
->dgroup
-1].selector
;
577 ECX_reg(&context
) = pModule
->heap_size
;
579 else /* hmm, DLL has no dgroup,
580 but why has it NE_FFLAGS_SINGLEDATA set ?
581 Buggy DLL compiler ? */
583 DS_reg(&context
) = 0;
584 ECX_reg(&context
) = 0;
588 CS_reg(&context
) = pSegTable
[pModule
->cs
-1].selector
;
589 EIP_reg(&context
) = pModule
->ip
;
590 EBP_reg(&context
) = OFFSETOF(THREAD_Current()->cur_stack
)
591 + (WORD
)&((STACK16FRAME
*)0)->bp
;
592 EDI_reg(&context
) = DS_reg(&context
) ? DS_reg(&context
) : hModule
;
595 pModule
->cs
= 0; /* Don't initialize it twice */
596 TRACE(dll
, "Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
597 CS_reg(&context
), IP_reg(&context
), DS_reg(&context
),
598 DI_reg(&context
), CX_reg(&context
) );
599 Callbacks
->CallRegisterShortProc( &context
, 0 );
604 /***********************************************************************
607 * Recursively initialize all DLLs (according to the order in which
608 * they where loaded).
610 void NE_InitializeDLLs( HMODULE16 hModule
)
612 TDB
* pTask
= (TDB
*)GlobalLock16(GetCurrentTask());
616 if (!(pModule
= MODULE_GetPtr16( hModule
))) return;
617 if (pModule
->flags
& NE_FFLAGS_WIN32
) return;
619 if (pModule
->dlls_to_init
)
621 HGLOBAL16 to_init
= pModule
->dlls_to_init
;
622 pModule
->dlls_to_init
= 0;
623 for (pDLL
= (HMODULE16
*)GlobalLock16( to_init
); *pDLL
; pDLL
++)
625 NE_InitializeDLLs( *pDLL
);
627 GlobalFree16( to_init
);
629 NE_InitDLL( pTask
, hModule
);
633 /***********************************************************************
636 * Needed for self-loading modules.
639 /* It does nothing */
640 void WINAPI
PatchCodeHandle(HANDLE16 hSel
)
642 fprintf(stderr
,"PatchCodeHandle(%04x),stub!\n",hSel
);
646 /***********************************************************************
649 * This function translates NE segment flags to GlobalAlloc flags
651 static WORD
NE_Ne2MemFlags(WORD flags
)
655 if (flags
& NE_SEGFLAGS_DISCARDABLE
)
656 memflags
|= GMEM_DISCARDABLE
;
657 if (flags
& NE_SEGFLAGS_MOVEABLE
||
658 ( ! (flags
& NE_SEGFLAGS_DATA
) &&
659 ! (flags
& NE_SEGFLAGS_LOADED
) &&
660 ! (flags
& NE_SEGFLAGS_ALLOCATED
)
663 memflags
|= GMEM_MOVEABLE
;
664 memflags
|= GMEM_ZEROINIT
;
666 memflags
= GMEM_ZEROINIT
| GMEM_FIXED
;
671 /***********************************************************************
672 * NE_AllocateSegment (WPROCS.26)
674 DWORD WINAPI
NE_AllocateSegment( WORD wFlags
, WORD wSize
, WORD wElem
)
676 WORD size
= wSize
<< wElem
;
677 HANDLE16 hMem
= GlobalAlloc16( NE_Ne2MemFlags(wFlags
), size
);
678 return MAKELONG( hMem
, GlobalHandleToSel(hMem
) );
682 /***********************************************************************
685 BOOL32
NE_CreateSegments( HMODULE16 hModule
)
687 SEGTABLEENTRY
*pSegment
;
691 if (!(pModule
= MODULE_GetPtr16( hModule
))) return FALSE
;
692 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
694 pSegment
= NE_SEG_TABLE( pModule
);
695 for (i
= 1; i
<= pModule
->seg_count
; i
++, pSegment
++)
697 minsize
= pSegment
->minsize
? pSegment
->minsize
: 0x10000;
698 if (i
== pModule
->ss
) minsize
+= pModule
->stack_size
;
699 /* The DGROUP is allocated by MODULE_CreateInstance */
700 if (i
== pModule
->dgroup
) continue;
701 pSegment
->selector
= GLOBAL_Alloc( NE_Ne2MemFlags(pSegment
->flags
),
703 !(pSegment
->flags
& NE_SEGFLAGS_DATA
),
705 FALSE
/*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
706 if (!pSegment
->selector
) return FALSE
;
709 pModule
->dgroup_entry
= pModule
->dgroup
? pModule
->seg_table
+
710 (pModule
->dgroup
- 1) * sizeof(SEGTABLEENTRY
) : 0;