2 * Selector manipulation functions
4 * Copyright 1995 Alexandre Julliard
11 #include "selectors.h"
12 #include "stackframe.h"
16 #define FIRST_LDT_ENTRY_TO_ALLOC 17
19 /***********************************************************************
20 * AllocSelectorArray (KERNEL.206)
22 WORD WINAPI
AllocSelectorArray( WORD count
)
24 WORD i
, sel
, size
= 0;
28 for (i
= FIRST_LDT_ENTRY_TO_ALLOC
; i
< LDT_SIZE
; i
++)
30 if (!IS_LDT_ENTRY_FREE(i
)) size
= 0;
31 else if (++size
>= count
) break;
33 if (i
== LDT_SIZE
) return 0;
37 entry
.type
= SEGMENT_DATA
;
38 entry
.seg_32bit
= FALSE
;
39 entry
.read_only
= FALSE
;
40 entry
.limit_in_pages
= FALSE
;
41 entry
.limit
= 1; /* avoid 0 base and limit */
43 for (i
= 0; i
< count
; i
++)
45 /* Mark selector as allocated */
46 ldt_flags_copy
[sel
+ i
] |= LDT_FLAGS_ALLOCATED
;
47 LDT_SetEntry( sel
+ i
, &entry
);
49 return ENTRY_TO_SELECTOR( sel
);
53 /***********************************************************************
54 * AllocSelector (KERNEL.175)
56 WORD WINAPI
AllocSelector( WORD sel
)
58 WORD newsel
, count
, i
;
60 count
= sel
? ((GET_SEL_LIMIT(sel
) >> 16) + 1) : 1;
61 newsel
= AllocSelectorArray( count
);
62 TRACE(selector
, "(%04x): returning %04x\n",
64 if (!newsel
) return 0;
65 if (!sel
) return newsel
; /* nothing to copy */
66 for (i
= 0; i
< count
; i
++)
69 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
) + i
, &entry
);
70 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel
) + i
, &entry
);
76 /***********************************************************************
77 * FreeSelector (KERNEL.176)
79 WORD WINAPI
FreeSelector( WORD sel
)
81 if (IS_SELECTOR_FREE(sel
)) return sel
; /* error */
82 SELECTOR_FreeBlock( sel
, 1 );
87 /***********************************************************************
90 * Set the LDT entries for an array of selectors.
92 static void SELECTOR_SetEntries( WORD sel
, const void *base
, DWORD size
,
93 enum seg_type type
, BOOL32 is32bit
,
99 /* The limit for the first selector is the whole */
100 /* block. The next selectors get a 64k limit. */
101 entry
.base
= (unsigned long)base
;
103 entry
.seg_32bit
= is32bit
;
104 entry
.read_only
= readonly
;
105 entry
.limit_in_pages
= (size
> 0x100000);
106 if (entry
.limit_in_pages
) entry
.limit
= ((size
+ 0xfff) >> 12) - 1;
107 else entry
.limit
= size
- 1;
108 /* Make sure base and limit are not 0 together if the size is not 0 */
109 if (!base
&& !entry
.limit
&& size
) entry
.limit
= 1;
110 count
= (size
+ 0xffff) / 0x10000;
111 for (i
= 0; i
< count
; i
++)
113 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
) + i
, &entry
);
114 entry
.base
+= 0x10000;
115 /* Apparently the next selectors should *not* get a 64k limit. */
116 /* Can't remember where I read they should... --AJ */
117 entry
.limit
-= entry
.limit_in_pages
? 0x10 : 0x10000;
122 /***********************************************************************
123 * SELECTOR_AllocBlock
125 * Allocate selectors for a block of linear memory.
127 WORD
SELECTOR_AllocBlock( const void *base
, DWORD size
, enum seg_type type
,
128 BOOL32 is32bit
, BOOL32 readonly
)
133 count
= (size
+ 0xffff) / 0x10000;
134 sel
= AllocSelectorArray( count
);
135 if (sel
) SELECTOR_SetEntries( sel
, base
, size
, type
, is32bit
, readonly
);
140 /***********************************************************************
143 * Free a block of selectors.
145 void SELECTOR_FreeBlock( WORD sel
, WORD count
)
151 TRACE(selector
, "(%04x,%d)\n", sel
, count
);
152 sel
&= ~(__AHINCR
- 1); /* clear bottom bits of selector */
153 nextsel
= sel
+ (count
<< __AHSHIFT
);
157 /* Check if we are freeing current %fs or %gs selector */
161 if ((fs
>= sel
) && (fs
< nextsel
))
163 fprintf( stderr
, "SELECTOR_FreeBlock: freeing %%fs selector (%04x), not good.\n", fs
);
167 if ((gs
>= sel
) && (gs
< nextsel
)) SET_GS( 0 );
169 #endif /* __i386__ */
171 memset( &entry
, 0, sizeof(entry
) ); /* clear the LDT entries */
172 for (i
= SELECTOR_TO_ENTRY(sel
); count
; i
++, count
--)
174 LDT_SetEntry( i
, &entry
);
175 ldt_flags_copy
[i
] &= ~LDT_FLAGS_ALLOCATED
;
178 /* Clear the saved 16-bit selector */
179 frame
= CURRENT_STACK16
;
182 if ((frame
->ds
>= sel
) && (frame
->ds
< nextsel
)) frame
->ds
= 0;
183 if ((frame
->es
>= sel
) && (frame
->es
< nextsel
)) frame
->es
= 0;
184 if (!frame
->frame32
) break;
185 frame
= PTR_SEG_TO_LIN( frame
->frame32
->frame16
);
190 /***********************************************************************
191 * SELECTOR_ReallocBlock
193 * Change the size of a block of selectors.
195 WORD
SELECTOR_ReallocBlock( WORD sel
, const void *base
, DWORD size
,
196 enum seg_type type
, BOOL32 is32bit
, BOOL32 readonly
)
198 WORD i
, oldcount
, newcount
;
201 oldcount
= (GET_SEL_LIMIT(sel
) >> 16) + 1;
202 newcount
= (size
+ 0xffff) >> 16;
204 if (oldcount
< newcount
) /* We need to add selectors */
206 /* Check if the next selectors are free */
207 if (SELECTOR_TO_ENTRY(sel
) + newcount
> LDT_SIZE
) i
= oldcount
;
209 for (i
= oldcount
; i
< newcount
; i
++)
210 if (!IS_LDT_ENTRY_FREE(SELECTOR_TO_ENTRY(sel
)+i
)) break;
212 if (i
< newcount
) /* they are not free */
214 SELECTOR_FreeBlock( sel
, oldcount
);
215 sel
= AllocSelectorArray( newcount
);
217 else /* mark the selectors as allocated */
219 for (i
= oldcount
; i
< newcount
; i
++)
220 ldt_flags_copy
[SELECTOR_TO_ENTRY(sel
)+i
] |=LDT_FLAGS_ALLOCATED
;
223 else if (oldcount
> newcount
) /* We need to remove selectors */
225 SELECTOR_FreeBlock( ENTRY_TO_SELECTOR(SELECTOR_TO_ENTRY(sel
)+newcount
),
226 oldcount
- newcount
);
228 if (sel
) SELECTOR_SetEntries( sel
, base
, size
, type
, is32bit
, readonly
);
233 /***********************************************************************
234 * PrestoChangoSelector (KERNEL.177)
236 WORD WINAPI
PrestoChangoSelector( WORD selSrc
, WORD selDst
)
239 LDT_GetEntry( SELECTOR_TO_ENTRY( selSrc
), &entry
);
240 entry
.type
^= SEGMENT_CODE
; /* toggle the executable bit */
241 LDT_SetEntry( SELECTOR_TO_ENTRY( selDst
), &entry
);
246 /***********************************************************************
247 * AllocCStoDSAlias (KERNEL.170)
249 WORD WINAPI
AllocCStoDSAlias( WORD sel
)
254 newsel
= AllocSelectorArray( 1 );
255 TRACE(selector
, "(%04x): returning %04x\n",
257 if (!newsel
) return 0;
258 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
259 entry
.type
= SEGMENT_DATA
;
260 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel
), &entry
);
265 /***********************************************************************
266 * AllocDStoCSAlias (KERNEL.171)
268 WORD WINAPI
AllocDStoCSAlias( WORD sel
)
273 newsel
= AllocSelectorArray( 1 );
274 TRACE(selector
, "(%04x): returning %04x\n",
276 if (!newsel
) return 0;
277 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
278 entry
.type
= SEGMENT_CODE
;
279 LDT_SetEntry( SELECTOR_TO_ENTRY(newsel
), &entry
);
284 /***********************************************************************
285 * LongPtrAdd (KERNEL.180)
287 void WINAPI
LongPtrAdd( DWORD ptr
, DWORD add
)
290 LDT_GetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr
)), &entry
);
292 LDT_SetEntry( SELECTOR_TO_ENTRY(SELECTOROF(ptr
)), &entry
);
296 /***********************************************************************
297 * GetSelectorBase (KERNEL.186)
299 DWORD WINAPI
GetSelectorBase( WORD sel
)
301 DWORD base
= GET_SEL_BASE(sel
);
303 /* if base points into DOSMEM, assume we have to
304 * return pointer into physical lower 1MB */
306 return DOSMEM_MapLinearToDos( (LPVOID
)base
);
310 /***********************************************************************
311 * SetSelectorBase (KERNEL.187)
313 WORD WINAPI
SetSelectorBase( WORD sel
, DWORD base
)
317 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
319 entry
.base
= (DWORD
)DOSMEM_MapDosToLinear(base
);
321 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
326 /***********************************************************************
327 * GetSelectorLimit (KERNEL.188)
329 DWORD WINAPI
GetSelectorLimit( WORD sel
)
331 return GET_SEL_LIMIT(sel
);
335 /***********************************************************************
336 * SetSelectorLimit (KERNEL.189)
338 WORD WINAPI
SetSelectorLimit( WORD sel
, DWORD limit
)
341 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
342 entry
.limit_in_pages
= (limit
>= 0x100000);
343 if (entry
.limit_in_pages
) entry
.limit
= limit
>> 12;
344 else entry
.limit
= limit
;
345 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
350 /***********************************************************************
351 * SelectorAccessRights (KERNEL.196)
353 WORD WINAPI
SelectorAccessRights( WORD sel
, WORD op
, WORD val
)
356 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
357 if (op
== 0) /* get */
359 return 0x01 | /* accessed */
360 0x10 | /* not system */
363 ((entry
.read_only
== 0) << 1) |
365 (entry
.seg_32bit
<< 14) |
366 (entry
.limit_in_pages
<< 15);
370 entry
.read_only
= ((val
& 2) == 0);
371 entry
.type
= (val
>> 2) & 3;
372 entry
.seg_32bit
= val
& 0x4000;
373 entry
.limit_in_pages
= val
& 0x8000;
374 LDT_SetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
380 /***********************************************************************
381 * IsBadCodePtr16 (KERNEL.336)
383 BOOL16 WINAPI
IsBadCodePtr16( SEGPTR lpfn
)
388 sel
= SELECTOROF(lpfn
);
389 if (!sel
) return TRUE
;
390 if (IS_SELECTOR_FREE(sel
)) return TRUE
;
391 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
392 if (entry
.type
!= SEGMENT_CODE
) return TRUE
;
393 if (OFFSETOF(lpfn
) > entry
.limit
) return TRUE
;
398 /***********************************************************************
399 * IsBadStringPtr16 (KERNEL.337)
401 BOOL16 WINAPI
IsBadStringPtr16( SEGPTR ptr
, UINT16 size
)
406 sel
= SELECTOROF(ptr
);
407 if (!sel
) return TRUE
;
408 if (IS_SELECTOR_FREE(sel
)) return TRUE
;
409 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
410 if ((entry
.type
== SEGMENT_CODE
) && entry
.read_only
) return TRUE
;
411 if (strlen(PTR_SEG_TO_LIN(ptr
)) < size
) size
= strlen(PTR_SEG_TO_LIN(ptr
));
412 if (OFFSETOF(ptr
) + size
- 1 > entry
.limit
) return TRUE
;
417 /***********************************************************************
418 * IsBadHugeReadPtr16 (KERNEL.346)
420 BOOL16 WINAPI
IsBadHugeReadPtr16( SEGPTR ptr
, DWORD size
)
425 sel
= SELECTOROF(ptr
);
426 if (!sel
) return TRUE
;
427 if (IS_SELECTOR_FREE(sel
)) return TRUE
;
428 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
429 if ((entry
.type
== SEGMENT_CODE
) && entry
.read_only
) return TRUE
;
430 if (OFFSETOF(ptr
) + size
- 1 > entry
.limit
) return TRUE
;
435 /***********************************************************************
436 * IsBadHugeWritePtr16 (KERNEL.347)
438 BOOL16 WINAPI
IsBadHugeWritePtr16( SEGPTR ptr
, DWORD size
)
443 sel
= SELECTOROF(ptr
);
444 if (!sel
) return TRUE
;
445 if (IS_SELECTOR_FREE(sel
)) return TRUE
;
446 LDT_GetEntry( SELECTOR_TO_ENTRY(sel
), &entry
);
447 if ((entry
.type
== SEGMENT_CODE
) || entry
.read_only
) return TRUE
;
448 if (OFFSETOF(ptr
) + size
- 1 > entry
.limit
) return TRUE
;
452 /***********************************************************************
453 * IsBadReadPtr16 (KERNEL.334)
455 BOOL16 WINAPI
IsBadReadPtr16( SEGPTR ptr
, UINT16 size
)
457 return IsBadHugeReadPtr16( ptr
, size
);
461 /***********************************************************************
462 * IsBadWritePtr16 (KERNEL.335)
464 BOOL16 WINAPI
IsBadWritePtr16( SEGPTR ptr
, UINT16 size
)
466 return IsBadHugeWritePtr16( ptr
, size
);
470 /***********************************************************************
471 * MemoryRead (TOOLHELP.78)
473 DWORD WINAPI
MemoryRead( WORD sel
, DWORD offset
, void *buffer
, DWORD count
)
475 if (IS_SELECTOR_FREE(sel
)) return 0;
476 if (offset
> GET_SEL_LIMIT(sel
)) return 0;
477 if (offset
+ count
> GET_SEL_LIMIT(sel
) + 1)
478 count
= GET_SEL_LIMIT(sel
) + 1 - offset
;
479 memcpy( buffer
, ((char *)GET_SEL_BASE(sel
)) + offset
, count
);
484 /***********************************************************************
485 * MemoryWrite (TOOLHELP.79)
487 DWORD WINAPI
MemoryWrite( WORD sel
, DWORD offset
, void *buffer
, DWORD count
)
489 if (IS_SELECTOR_FREE(sel
)) return 0;
490 if (offset
> GET_SEL_LIMIT(sel
)) return 0;
491 if (offset
+ count
> GET_SEL_LIMIT(sel
) + 1)
492 count
= GET_SEL_LIMIT(sel
) + 1 - offset
;
493 memcpy( ((char *)GET_SEL_BASE(sel
)) + offset
, buffer
, count
);
497 /************************************* Win95 pointer mapping functions *
499 * NOTE: MapSLFix and UnMapSLFixArray are probably needed to prevent
500 * unexpected linear address change when GlobalCompact() shuffles
504 /***********************************************************************
505 * MapSL (KERNEL32.662)
507 * Maps fixed segmented pointer to linear.
509 LPVOID WINAPI
MapSL( SEGPTR sptr
)
511 return (LPVOID
)PTR_SEG_TO_LIN(sptr
);
515 /***********************************************************************
516 * MapLS (KERNEL32.679)
518 * Maps linear pointer to segmented.
520 SEGPTR WINAPI
MapLS( LPVOID ptr
)
522 WORD sel
= SELECTOR_AllocBlock( ptr
, 0x10000, SEGMENT_DATA
, FALSE
, FALSE
);
523 return PTR_SEG_OFF_TO_SEGPTR( sel
, 0 );
527 /***********************************************************************
528 * UnMapLS (KERNEL32.680)
530 * Free mapped selector.
532 void WINAPI
UnMapLS( SEGPTR sptr
)
534 if (!__winelib
) SELECTOR_FreeBlock( SELECTOROF(sptr
), 1 );
537 /***********************************************************************
538 * GetThreadSelectorEntry (KERNEL32)
539 * FIXME: add #ifdef i386 for non x86
541 BOOL32 WINAPI
GetThreadSelectorEntry( HANDLE32 hthread
, DWORD sel
,
546 LDT_GetEntry(SELECTOR_TO_ENTRY(sel
),&ldtentry
);
547 ldtent
->BaseLow
= ldtentry
.base
& 0x0000ffff;
548 ldtent
->HighWord
.Bits
.BaseMid
= (ldtentry
.base
& 0x00ff0000) >> 16;
549 ldtent
->HighWord
.Bits
.BaseHi
= (ldtentry
.base
& 0xff000000) >> 24;
550 ldtent
->LimitLow
= ldtentry
.limit
& 0x0000ffff;
551 ldtent
->HighWord
.Bits
.LimitHi
= (ldtentry
.limit
& 0x00ff0000) >> 16;
552 ldtent
->HighWord
.Bits
.Dpl
= 3;
553 ldtent
->HighWord
.Bits
.Sys
= 0;
554 ldtent
->HighWord
.Bits
.Pres
= 1;
555 ldtent
->HighWord
.Bits
.Type
= 0x10|(ldtentry
.type
<< 2);
556 if (ldtentry
.read_only
)
557 ldtent
->HighWord
.Bits
.Type
|=0x2;
558 ldtent
->HighWord
.Bits
.Granularity
= ldtentry
.limit_in_pages
;
559 ldtent
->HighWord
.Bits
.Default_Big
= ldtentry
.seg_32bit
;
564 /**********************************************************************
566 * These functions map linear pointers at [EBP+xxx] to segmented pointers
568 * Win95 uses some kind of alias structs, which it stores in [EBP+x] to
569 * unravel them at SUnMapLS. We just store the segmented pointer there.
572 x_SMapLS_IP_EBP_x(CONTEXT
*context
,int argoff
) {
575 val
=*(DWORD
*)(EBP_reg(context
)+argoff
);
578 *(DWORD
*)(EBP_reg(context
)+argoff
) = 0;
580 ptr
= MapLS((LPVOID
)val
);
581 *(DWORD
*)(EBP_reg(context
)+argoff
) = ptr
;
583 EAX_reg(context
) = ptr
;
586 void WINAPI
SMapLS_IP_EBP_8(CONTEXT
*context
) {x_SMapLS_IP_EBP_x(context
,8);}
587 void WINAPI
SMapLS_IP_EBP_12(CONTEXT
*context
) {x_SMapLS_IP_EBP_x(context
,12);}
588 void WINAPI
SMapLS_IP_EBP_16(CONTEXT
*context
) {x_SMapLS_IP_EBP_x(context
,16);}
589 void WINAPI
SMapLS_IP_EBP_20(CONTEXT
*context
) {x_SMapLS_IP_EBP_x(context
,20);}
590 void WINAPI
SMapLS_IP_EBP_24(CONTEXT
*context
) {x_SMapLS_IP_EBP_x(context
,24);}
591 void WINAPI
SMapLS_IP_EBP_28(CONTEXT
*context
) {x_SMapLS_IP_EBP_x(context
,28);}
592 void WINAPI
SMapLS_IP_EBP_32(CONTEXT
*context
) {x_SMapLS_IP_EBP_x(context
,32);}
593 void WINAPI
SMapLS_IP_EBP_36(CONTEXT
*context
) {x_SMapLS_IP_EBP_x(context
,36);}
594 void WINAPI
SMapLS_IP_EBP_40(CONTEXT
*context
) {x_SMapLS_IP_EBP_x(context
,40);}
596 void WINAPI
SMapLS(CONTEXT
*context
)
598 if (EAX_reg(context
)>=0x10000) {
599 EAX_reg(context
) = MapLS((LPVOID
)EAX_reg(context
));
600 EDX_reg(context
) = EAX_reg(context
);
602 EDX_reg(context
) = 0;
606 void WINAPI
SUnMapLS(CONTEXT
*context
)
608 if (EAX_reg(context
)>=0x10000)
609 UnMapLS((SEGPTR
)EAX_reg(context
));
613 x_SUnMapLS_IP_EBP_x(CONTEXT
*context
,int argoff
) {
614 if (*(DWORD
*)(EBP_reg(context
)+argoff
))
615 UnMapLS(*(DWORD
*)(EBP_reg(context
)+argoff
));
616 *(DWORD
*)(EBP_reg(context
)+argoff
)=0;
618 void WINAPI
SUnMapLS_IP_EBP_8(CONTEXT
*context
) { x_SUnMapLS_IP_EBP_x(context
,12); }
619 void WINAPI
SUnMapLS_IP_EBP_12(CONTEXT
*context
) { x_SUnMapLS_IP_EBP_x(context
,12); }
620 void WINAPI
SUnMapLS_IP_EBP_16(CONTEXT
*context
) { x_SUnMapLS_IP_EBP_x(context
,16); }
621 void WINAPI
SUnMapLS_IP_EBP_20(CONTEXT
*context
) { x_SUnMapLS_IP_EBP_x(context
,20); }
622 void WINAPI
SUnMapLS_IP_EBP_24(CONTEXT
*context
) { x_SUnMapLS_IP_EBP_x(context
,24); }
623 void WINAPI
SUnMapLS_IP_EBP_28(CONTEXT
*context
) { x_SUnMapLS_IP_EBP_x(context
,28); }
624 void WINAPI
SUnMapLS_IP_EBP_32(CONTEXT
*context
) { x_SUnMapLS_IP_EBP_x(context
,32); }
625 void WINAPI
SUnMapLS_IP_EBP_36(CONTEXT
*context
) { x_SUnMapLS_IP_EBP_x(context
,36); }
626 void WINAPI
SUnMapLS_IP_EBP_40(CONTEXT
*context
) { x_SUnMapLS_IP_EBP_x(context
,40); }
628 /**********************************************************************
629 * WOWGetVDMPointer (KERNEL32.55)
630 * Get linear from segmented pointer. (MSDN lib)
632 LPVOID WINAPI
WOWGetVDMPointer(DWORD vp
,DWORD nrofbytes
,BOOL32
protected)
634 /* FIXME: add size check too */
636 return PTR_SEG_TO_LIN(vp
);
638 return DOSMEM_MapRealToLinear(vp
);
641 /**********************************************************************
642 * GetVDMPointer32W (KERNEL.516)
644 LPVOID WINAPI
GetVDMPointer32W(DWORD vp
,DWORD mode
)
646 return WOWGetVDMPointer(vp
,0,mode
);
649 /**********************************************************************
650 * WOWGetVDMPointerFix (KERNEL32.55)
651 * Dito, but fix heapsegment (MSDN lib)
653 LPVOID WINAPI
WOWGetVDMPointerFix(DWORD vp
,DWORD nrofbytes
,BOOL32
protected)
655 /* FIXME: fix heapsegment */
656 return WOWGetVDMPointer(vp
,nrofbytes
,protected);
659 /**********************************************************************
660 * WOWGetVDMPointerUnFix (KERNEL32.56)
662 void WINAPI
WOWGetVDMPointerUnfix(DWORD vp
)
664 /* FIXME: unfix heapsegment */
667 /***********************************************************************
668 * UTSelectorOffsetToLinear (WIN32S16.48)
670 * rough guesswork, but seems to work (I had no "reasonable" docu)
672 LPVOID WINAPI
UTSelectorOffsetToLinear(SEGPTR sptr
)
674 return PTR_SEG_TO_LIN(sptr
);
677 /***********************************************************************
678 * UTLinearToSelectorOffset (WIN32S16.49)
680 * FIXME: I don't know if that's the right way to do linear -> segmented
682 SEGPTR WINAPI
UTLinearToSelectorOffset(LPVOID lptr
)
684 fprintf( stderr
, "UTLinearToSelectorOffset(%p): stub\n", lptr
);