strmbase: Add support for rendering algorithms to quality control.
[wine] / dlls / krnl386.exe16 / selector.c
1 /*
2  * Selector manipulation functions
3  *
4  * Copyright 1995 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <string.h>
25
26 #include "wine/winbase16.h"
27 #include "wine/server.h"
28 #include "wine/debug.h"
29 #include "kernel16_private.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(selector);
32
33 #define LDT_SIZE 8192
34
35 /* get the number of selectors needed to cover up to the selector limit */
36 static inline WORD get_sel_count( WORD sel )
37 {
38     return (wine_ldt_copy.limit[sel >> __AHSHIFT] >> 16) + 1;
39 }
40
41
42 /***********************************************************************
43  *           AllocSelectorArray   (KERNEL.206)
44  */
45 WORD WINAPI AllocSelectorArray16( WORD count )
46 {
47     WORD i, sel = wine_ldt_alloc_entries( count );
48
49     if (sel)
50     {
51         LDT_ENTRY entry;
52         wine_ldt_set_base( &entry, 0 );
53         wine_ldt_set_limit( &entry, 1 ); /* avoid 0 base and limit */
54         wine_ldt_set_flags( &entry, WINE_LDT_FLAGS_DATA );
55         for (i = 0; i < count; i++) wine_ldt_set_entry( sel + (i << __AHSHIFT), &entry );
56     }
57     return sel;
58 }
59
60
61 /***********************************************************************
62  *           AllocSelector   (KERNEL.175)
63  */
64 WORD WINAPI AllocSelector16( WORD sel )
65 {
66     WORD newsel, count, i;
67
68     count = sel ? get_sel_count(sel) : 1;
69     newsel = wine_ldt_alloc_entries( count );
70     TRACE("(%04x): returning %04x\n", sel, newsel );
71     if (!newsel) return 0;
72     if (!sel) return newsel;  /* nothing to copy */
73     for (i = 0; i < count; i++)
74     {
75         LDT_ENTRY entry;
76         wine_ldt_get_entry( sel + (i << __AHSHIFT), &entry );
77         wine_ldt_set_entry( newsel + (i << __AHSHIFT), &entry );
78     }
79     return newsel;
80 }
81
82
83 /***********************************************************************
84  *           FreeSelector   (KERNEL.176)
85  */
86 WORD WINAPI FreeSelector16( WORD sel )
87 {
88     LDT_ENTRY entry;
89
90     wine_ldt_get_entry( sel, &entry );
91     if (wine_ldt_is_empty( &entry )) return sel;  /* error */
92     /* Check if we are freeing current %fs selector */
93     if (!((wine_get_fs() ^ sel) & ~3))
94         WARN("Freeing %%fs selector (%04x), not good.\n", wine_get_fs() );
95     wine_ldt_free_entries( sel, 1 );
96     return 0;
97 }
98
99
100 /***********************************************************************
101  *           SELECTOR_SetEntries
102  *
103  * Set the LDT entries for an array of selectors.
104  */
105 static void SELECTOR_SetEntries( WORD sel, const void *base, DWORD size, unsigned char flags )
106 {
107     LDT_ENTRY entry;
108     WORD i, count;
109
110     wine_ldt_set_base( &entry, base );
111     wine_ldt_set_limit( &entry, size - 1 );
112     wine_ldt_set_flags( &entry, flags );
113     count = (size + 0xffff) / 0x10000;
114     for (i = 0; i < count; i++)
115     {
116         wine_ldt_set_entry( sel + (i << __AHSHIFT), &entry );
117         wine_ldt_set_base( &entry, (char*)wine_ldt_get_base(&entry) + 0x10000);
118         /* yep, Windows sets limit like that, not 64K sel units */
119         wine_ldt_set_limit( &entry, wine_ldt_get_limit(&entry) - 0x10000 );
120     }
121 }
122
123
124 /***********************************************************************
125  *           SELECTOR_AllocBlock
126  *
127  * Allocate selectors for a block of linear memory.
128  */
129 WORD SELECTOR_AllocBlock( const void *base, DWORD size, unsigned char flags )
130 {
131     WORD sel, count;
132
133     if (!size) return 0;
134     count = (size + 0xffff) / 0x10000;
135     sel = wine_ldt_alloc_entries( count );
136     if (sel) SELECTOR_SetEntries( sel, base, size, flags );
137     return sel;
138 }
139
140
141 /***********************************************************************
142  *           SELECTOR_FreeBlock
143  *
144  * Free a block of selectors.
145  */
146 void SELECTOR_FreeBlock( WORD sel )
147 {
148     WORD i, count = get_sel_count( sel );
149
150     TRACE("(%04x,%d)\n", sel, count );
151     for (i = 0; i < count; i++) FreeSelector16( sel + (i << __AHSHIFT) );
152 }
153
154
155 /***********************************************************************
156  *           SELECTOR_ReallocBlock
157  *
158  * Change the size of a block of selectors.
159  */
160 WORD SELECTOR_ReallocBlock( WORD sel, const void *base, DWORD size )
161 {
162     LDT_ENTRY entry;
163     int oldcount, newcount;
164
165     if (!size) size = 1;
166     wine_ldt_get_entry( sel, &entry );
167     oldcount = (wine_ldt_get_limit(&entry) >> 16) + 1;
168     newcount = (size + 0xffff) >> 16;
169
170     sel = wine_ldt_realloc_entries( sel, oldcount, newcount );
171     if (sel) SELECTOR_SetEntries( sel, base, size, wine_ldt_get_flags(&entry) );
172     return sel;
173 }
174
175
176 /***********************************************************************
177  *           PrestoChangoSelector   (KERNEL.177)
178  */
179 WORD WINAPI PrestoChangoSelector16( WORD selSrc, WORD selDst )
180 {
181     LDT_ENTRY entry;
182     wine_ldt_get_entry( selSrc, &entry );
183     /* toggle the executable bit */
184     entry.HighWord.Bits.Type ^= (WINE_LDT_FLAGS_CODE ^ WINE_LDT_FLAGS_DATA);
185     wine_ldt_set_entry( selDst, &entry );
186     return selDst;
187 }
188
189
190 /***********************************************************************
191  *           AllocCStoDSAlias   (KERNEL.170)
192  *           AllocAlias         (KERNEL.172)
193  */
194 WORD WINAPI AllocCStoDSAlias16( WORD sel )
195 {
196     WORD newsel;
197     LDT_ENTRY entry;
198
199     newsel = wine_ldt_alloc_entries( 1 );
200     TRACE("(%04x): returning %04x\n",
201                       sel, newsel );
202     if (!newsel) return 0;
203     wine_ldt_get_entry( sel, &entry );
204     entry.HighWord.Bits.Type = WINE_LDT_FLAGS_DATA;
205     wine_ldt_set_entry( newsel, &entry );
206     return newsel;
207 }
208
209
210 /***********************************************************************
211  *           AllocDStoCSAlias   (KERNEL.171)
212  */
213 WORD WINAPI AllocDStoCSAlias16( WORD sel )
214 {
215     WORD newsel;
216     LDT_ENTRY entry;
217
218     newsel = wine_ldt_alloc_entries( 1 );
219     TRACE("(%04x): returning %04x\n",
220                       sel, newsel );
221     if (!newsel) return 0;
222     wine_ldt_get_entry( sel, &entry );
223     entry.HighWord.Bits.Type = WINE_LDT_FLAGS_CODE;
224     wine_ldt_set_entry( newsel, &entry );
225     return newsel;
226 }
227
228
229 /***********************************************************************
230  *           LongPtrAdd   (KERNEL.180)
231  */
232 void WINAPI LongPtrAdd16( DWORD ptr, DWORD add )
233 {
234     LDT_ENTRY entry;
235     wine_ldt_get_entry( SELECTOROF(ptr), &entry );
236     wine_ldt_set_base( &entry, (char *)wine_ldt_get_base(&entry) + add );
237     wine_ldt_set_entry( SELECTOROF(ptr), &entry );
238 }
239
240
241 /***********************************************************************
242  *             GetSelectorBase   (KERNEL.186)
243  */
244 DWORD WINAPI GetSelectorBase( WORD sel )
245 {
246     void *base = wine_ldt_copy.base[sel >> __AHSHIFT];
247
248     /* if base points into DOSMEM, assume we have to
249      * return pointer into physical lower 1MB */
250
251     return DOSMEM_MapLinearToDos( base );
252 }
253
254
255 /***********************************************************************
256  *             SetSelectorBase   (KERNEL.187)
257  */
258 WORD WINAPI SetSelectorBase( WORD sel, DWORD base )
259 {
260     LDT_ENTRY entry;
261     wine_ldt_get_entry( sel, &entry );
262     wine_ldt_set_base( &entry, DOSMEM_MapDosToLinear(base) );
263     wine_ldt_set_entry( sel, &entry );
264     return sel;
265 }
266
267
268 /***********************************************************************
269  *           GetSelectorLimit   (KERNEL.188)
270  */
271 DWORD WINAPI GetSelectorLimit16( WORD sel )
272 {
273     return wine_ldt_copy.limit[sel >> __AHSHIFT];
274 }
275
276
277 /***********************************************************************
278  *           SetSelectorLimit   (KERNEL.189)
279  */
280 WORD WINAPI SetSelectorLimit16( WORD sel, DWORD limit )
281 {
282     LDT_ENTRY entry;
283     wine_ldt_get_entry( sel, &entry );
284     wine_ldt_set_limit( &entry, limit );
285     wine_ldt_set_entry( sel, &entry );
286     return sel;
287 }
288
289
290 /***********************************************************************
291  *           SelectorAccessRights   (KERNEL.196)
292  */
293 WORD WINAPI SelectorAccessRights16( WORD sel, WORD op, WORD val )
294 {
295     LDT_ENTRY entry;
296     wine_ldt_get_entry( sel, &entry );
297
298     if (op == 0)  /* get */
299     {
300         return entry.HighWord.Bytes.Flags1 | ((entry.HighWord.Bytes.Flags2 << 8) & 0xf0);
301     }
302     else  /* set */
303     {
304         entry.HighWord.Bytes.Flags1 = LOBYTE(val) | 0xf0;
305         entry.HighWord.Bytes.Flags2 = (entry.HighWord.Bytes.Flags2 & 0x0f) | (HIBYTE(val) & 0xf0);
306         wine_ldt_set_entry( sel, &entry );
307         return 0;
308     }
309 }
310
311
312 /***********************************************************************
313  *           IsBadCodePtr   (KERNEL.336)
314  */
315 BOOL16 WINAPI IsBadCodePtr16( SEGPTR lpfn )
316 {
317     WORD sel;
318     LDT_ENTRY entry;
319
320     sel = SELECTOROF(lpfn);
321     if (!sel) return TRUE;
322     wine_ldt_get_entry( sel, &entry );
323     if (wine_ldt_is_empty( &entry )) return TRUE;
324     /* check for code segment, ignoring conforming, read-only and accessed bits */
325     if ((entry.HighWord.Bits.Type ^ WINE_LDT_FLAGS_CODE) & 0x18) return TRUE;
326     if (OFFSETOF(lpfn) > wine_ldt_get_limit(&entry)) return TRUE;
327     return FALSE;
328 }
329
330
331 /***********************************************************************
332  *           IsBadStringPtr   (KERNEL.337)
333  */
334 BOOL16 WINAPI IsBadStringPtr16( SEGPTR ptr, UINT16 size )
335 {
336     WORD sel;
337     LDT_ENTRY entry;
338
339     sel = SELECTOROF(ptr);
340     if (!sel) return TRUE;
341     wine_ldt_get_entry( sel, &entry );
342     if (wine_ldt_is_empty( &entry )) return TRUE;
343     /* check for data or readable code segment */
344     if (!(entry.HighWord.Bits.Type & 0x10)) return TRUE;  /* system descriptor */
345     if ((entry.HighWord.Bits.Type & 0x0a) == 0x08) return TRUE;  /* non-readable code segment */
346     if (strlen(MapSL(ptr)) < size) size = strlen(MapSL(ptr)) + 1;
347     if (size && (OFFSETOF(ptr) + size - 1 > wine_ldt_get_limit(&entry))) return TRUE;
348     return FALSE;
349 }
350
351
352 /***********************************************************************
353  *           IsBadHugeReadPtr   (KERNEL.346)
354  */
355 BOOL16 WINAPI IsBadHugeReadPtr16( SEGPTR ptr, DWORD size )
356 {
357     WORD sel;
358     LDT_ENTRY entry;
359
360     sel = SELECTOROF(ptr);
361     if (!sel) return TRUE;
362     wine_ldt_get_entry( sel, &entry );
363     if (wine_ldt_is_empty( &entry )) return TRUE;
364     /* check for data or readable code segment */
365     if (!(entry.HighWord.Bits.Type & 0x10)) return TRUE;  /* system descriptor */
366     if ((entry.HighWord.Bits.Type & 0x0a) == 0x08) return TRUE;  /* non-readable code segment */
367     if (size && (OFFSETOF(ptr) + size - 1 > wine_ldt_get_limit( &entry ))) return TRUE;
368     return FALSE;
369 }
370
371
372 /***********************************************************************
373  *           IsBadHugeWritePtr   (KERNEL.347)
374  */
375 BOOL16 WINAPI IsBadHugeWritePtr16( SEGPTR ptr, DWORD size )
376 {
377     WORD sel;
378     LDT_ENTRY entry;
379
380     sel = SELECTOROF(ptr);
381     if (!sel) return TRUE;
382     wine_ldt_get_entry( sel, &entry );
383     if (wine_ldt_is_empty( &entry )) return TRUE;
384     /* check for writable data segment, ignoring expand-down and accessed flags */
385     if ((entry.HighWord.Bits.Type ^ WINE_LDT_FLAGS_DATA) & ~5) return TRUE;
386     if (size && (OFFSETOF(ptr) + size - 1 > wine_ldt_get_limit( &entry ))) return TRUE;
387     return FALSE;
388 }
389
390 /***********************************************************************
391  *           IsBadReadPtr   (KERNEL.334)
392  */
393 BOOL16 WINAPI IsBadReadPtr16( SEGPTR ptr, UINT16 size )
394 {
395     return IsBadHugeReadPtr16( ptr, size );
396 }
397
398
399 /***********************************************************************
400  *           IsBadWritePtr   (KERNEL.335)
401  */
402 BOOL16 WINAPI IsBadWritePtr16( SEGPTR ptr, UINT16 size )
403 {
404     return IsBadHugeWritePtr16( ptr, size );
405 }
406
407
408 /***********************************************************************
409  *           IsBadFlatReadWritePtr   (KERNEL.627)
410  */
411 BOOL16 WINAPI IsBadFlatReadWritePtr16( SEGPTR ptr, DWORD size, BOOL16 bWrite )
412 {
413     return bWrite? IsBadHugeWritePtr16( ptr, size )
414                  : IsBadHugeReadPtr16( ptr, size );
415 }
416
417
418 /************************************* Win95 pointer mapping functions *
419  *
420  */
421
422 struct mapls_entry
423 {
424     struct mapls_entry *next;
425     void               *addr;   /* linear address */
426     int                 count;  /* ref count */
427     WORD                sel;    /* selector */
428 };
429
430 static struct mapls_entry *first_entry;
431
432
433 /***********************************************************************
434  *           MapLS   (KERNEL32.@)
435  *           MapLS   (KERNEL.358)
436  *
437  * Maps linear pointer to segmented.
438  */
439 SEGPTR WINAPI MapLS( LPCVOID ptr )
440 {
441     struct mapls_entry *entry, *free = NULL;
442     const void *base;
443     SEGPTR ret = 0;
444
445     if (!HIWORD(ptr)) return (SEGPTR)LOWORD(ptr);
446
447     base = (const char *)ptr - ((ULONG_PTR)ptr & 0x7fff);
448     HeapLock( GetProcessHeap() );
449     for (entry = first_entry; entry; entry = entry->next)
450     {
451         if (entry->addr == base) break;
452         if (!entry->count) free = entry;
453     }
454
455     if (!entry)
456     {
457         if (!free)  /* no free entry found, create a new one */
458         {
459             if (!(free = HeapAlloc( GetProcessHeap(), 0, sizeof(*free) ))) goto done;
460             if (!(free->sel = SELECTOR_AllocBlock( base, 0x10000, WINE_LDT_FLAGS_DATA )))
461             {
462                 HeapFree( GetProcessHeap(), 0, free );
463                 goto done;
464             }
465             free->count = 0;
466             free->next = first_entry;
467             first_entry = free;
468         }
469         SetSelectorBase( free->sel, (DWORD)base );
470         free->addr = (void*)base;
471         entry = free;
472     }
473     entry->count++;
474     ret = MAKESEGPTR( entry->sel, (const char *)ptr - (char *)entry->addr );
475  done:
476     HeapUnlock( GetProcessHeap() );
477     return ret;
478 }
479
480 /***********************************************************************
481  *           UnMapLS   (KERNEL32.@)
482  *           UnMapLS   (KERNEL.359)
483  *
484  * Free mapped selector.
485  */
486 void WINAPI UnMapLS( SEGPTR sptr )
487 {
488     struct mapls_entry *entry;
489     WORD sel = SELECTOROF(sptr);
490
491     if (sel)
492     {
493         HeapLock( GetProcessHeap() );
494         for (entry = first_entry; entry; entry = entry->next) if (entry->sel == sel) break;
495         if (entry && entry->count > 0) entry->count--;
496         HeapUnlock( GetProcessHeap() );
497     }
498 }
499
500 /***********************************************************************
501  *           MapSL   (KERNEL32.@)
502  *           MapSL   (KERNEL.357)
503  *
504  * Maps fixed segmented pointer to linear.
505  */
506 LPVOID WINAPI MapSL( SEGPTR sptr )
507 {
508     return (char *)wine_ldt_copy.base[SELECTOROF(sptr) >> __AHSHIFT] + OFFSETOF(sptr);
509 }
510
511 /***********************************************************************
512  *           MapSLFix   (KERNEL32.@)
513  *
514  * FIXME: MapSLFix and UnMapSLFixArray should probably prevent
515  * unexpected linear address change when GlobalCompact() shuffles
516  * moveable blocks.
517  */
518
519 LPVOID WINAPI MapSLFix( SEGPTR sptr )
520 {
521     return MapSL(sptr);
522 }
523
524
525 /***********************************************************************
526  *           UnMapSLFixArray   (KERNEL32.@)
527  *
528  * Must not change EAX, hence defined as asm function.
529  */
530 __ASM_STDCALL_FUNC( UnMapSLFixArray, 8, "ret $8" )
531
532 /***********************************************************************
533  *              SMapLS (KERNEL32.@)
534  */
535 __ASM_STDCALL_FUNC( SMapLS, 0,
536                    "xor %edx,%edx\n\t"
537                    "testl $0xffff0000,%eax\n\t"
538                    "jz 1f\n\t"
539                    "pushl %eax\n\t"
540                    "call " __ASM_NAME("MapLS") __ASM_STDCALL(4) "\n\t"
541                    "movl %eax,%edx\n"
542                    "1:\tret" )
543
544 /***********************************************************************
545  *              SUnMapLS (KERNEL32.@)
546  */
547 __ASM_STDCALL_FUNC( SUnMapLS, 0,
548                    "pushl %eax\n\t"  /* preserve eax */
549                    "pushl %eax\n\t"
550                    "call " __ASM_NAME("UnMapLS") __ASM_STDCALL(4) "\n\t"
551                    "popl %eax\n\t"
552                    "ret" )
553
554 /***********************************************************************
555  *              SMapLS_IP_EBP_8 (KERNEL32.@)
556  *
557  * These functions map linear pointers at [EBP+xxx] to segmented pointers
558  * and return them.
559  * Win95 uses some kind of alias structs, which it stores in [EBP+x] to
560  * unravel them at SUnMapLS. We just store the segmented pointer there.
561  */
562 __ASM_STDCALL_FUNC( SMapLS_IP_EBP_8, 0,
563                     "movl 8(%ebp),%eax\n\t"
564                     "call " __ASM_NAME("SMapLS") __ASM_STDCALL(4) "\n\t"
565                     "movl %edx,8(%ebp)\n\t"
566                     "ret" )
567
568 /***********************************************************************
569  *              SMapLS_IP_EBP_12 (KERNEL32.@)
570  */
571 __ASM_STDCALL_FUNC( SMapLS_IP_EBP_12, 0,
572                     "movl 12(%ebp),%eax\n\t"
573                     "call " __ASM_NAME("SMapLS") __ASM_STDCALL(4) "\n\t"
574                     "movl %edx,12(%ebp)\n\t"
575                     "ret" )
576
577 /***********************************************************************
578  *              SMapLS_IP_EBP_16 (KERNEL32.@)
579  */
580 __ASM_STDCALL_FUNC( SMapLS_IP_EBP_16, 0,
581                     "movl 16(%ebp),%eax\n\t"
582                     "call " __ASM_NAME("SMapLS") __ASM_STDCALL(4) "\n\t"
583                     "movl %edx,16(%ebp)\n\t"
584                     "ret" )
585
586 /***********************************************************************
587  *              SMapLS_IP_EBP_20 (KERNEL32.@)
588  */
589 __ASM_STDCALL_FUNC( SMapLS_IP_EBP_20, 0,
590                     "movl 20(%ebp),%eax\n\t"
591                     "call " __ASM_NAME("SMapLS") __ASM_STDCALL(4) "\n\t"
592                     "movl %edx,20(%ebp)\n\t"
593                     "ret" )
594
595 /***********************************************************************
596  *              SMapLS_IP_EBP_24 (KERNEL32.@)
597  */
598 __ASM_STDCALL_FUNC( SMapLS_IP_EBP_24, 0,
599                     "movl 24(%ebp),%eax\n\t"
600                     "call " __ASM_NAME("SMapLS") __ASM_STDCALL(4) "\n\t"
601                     "movl %edx,24(%ebp)\n\t"
602                     "ret" )
603
604 /***********************************************************************
605  *              SMapLS_IP_EBP_28 (KERNEL32.@)
606  */
607 __ASM_STDCALL_FUNC( SMapLS_IP_EBP_28, 0,
608                     "movl 28(%ebp),%eax\n\t"
609                     "call " __ASM_NAME("SMapLS") __ASM_STDCALL(4) "\n\t"
610                     "movl %edx,28(%ebp)\n\t"
611                     "ret" )
612
613 /***********************************************************************
614  *              SMapLS_IP_EBP_32 (KERNEL32.@)
615  */
616 __ASM_STDCALL_FUNC( SMapLS_IP_EBP_32, 0,
617                     "movl 32(%ebp),%eax\n\t"
618                     "call " __ASM_NAME("SMapLS") __ASM_STDCALL(4) "\n\t"
619                     "movl %edx,32(%ebp)\n\t"
620                     "ret" )
621
622 /***********************************************************************
623  *              SMapLS_IP_EBP_36 (KERNEL32.@)
624  */
625 __ASM_STDCALL_FUNC( SMapLS_IP_EBP_36, 0,
626                     "movl 36(%ebp),%eax\n\t"
627                     "call " __ASM_NAME("SMapLS") __ASM_STDCALL(4) "\n\t"
628                     "movl %edx,36(%ebp)\n\t"
629                     "ret" )
630
631 /***********************************************************************
632  *              SMapLS_IP_EBP_40 (KERNEL32.@)
633  */
634 __ASM_STDCALL_FUNC( SMapLS_IP_EBP_40, 0,
635                     "movl 40(%ebp),%eax\n\t"
636                     "call " __ASM_NAME("SMapLS") __ASM_STDCALL(4) "\n\t"
637                     "movl %edx,40(%ebp)\n\t"
638                     "ret" )
639
640 /***********************************************************************
641  *              SUnMapLS_IP_EBP_8 (KERNEL32.@)
642  */
643 __ASM_STDCALL_FUNC( SUnMapLS_IP_EBP_8, 0,
644                     "pushl %eax\n\t"  /* preserve eax */
645                     "pushl 8(%ebp)\n\t"
646                     "call " __ASM_NAME("UnMapLS") __ASM_STDCALL(4) "\n\t"
647                     "movl $0,8(%ebp)\n\t"
648                     "popl %eax\n\t"
649                     "ret" )
650
651 /***********************************************************************
652  *              SUnMapLS_IP_EBP_12 (KERNEL32.@)
653  */
654 __ASM_STDCALL_FUNC( SUnMapLS_IP_EBP_12, 0,
655                     "pushl %eax\n\t"  /* preserve eax */
656                     "pushl 12(%ebp)\n\t"
657                     "call " __ASM_NAME("UnMapLS") __ASM_STDCALL(4) "\n\t"
658                     "movl $0,12(%ebp)\n\t"
659                     "popl %eax\n\t"
660                     "ret" )
661
662 /***********************************************************************
663  *              SUnMapLS_IP_EBP_16 (KERNEL32.@)
664  */
665 __ASM_STDCALL_FUNC( SUnMapLS_IP_EBP_16, 0,
666                     "pushl %eax\n\t"  /* preserve eax */
667                     "pushl 16(%ebp)\n\t"
668                     "call " __ASM_NAME("UnMapLS") __ASM_STDCALL(4) "\n\t"
669                     "movl $0,16(%ebp)\n\t"
670                     "popl %eax\n\t"
671                     "ret" )
672
673 /***********************************************************************
674  *              SUnMapLS_IP_EBP_20 (KERNEL32.@)
675  */
676 __ASM_STDCALL_FUNC( SUnMapLS_IP_EBP_20, 0,
677                     "pushl %eax\n\t"  /* preserve eax */
678                     "pushl 20(%ebp)\n\t"
679                     "call " __ASM_NAME("UnMapLS") __ASM_STDCALL(4) "\n\t"
680                     "movl $0,20(%ebp)\n\t"
681                     "popl %eax\n\t"
682                     "ret" )
683
684 /***********************************************************************
685  *              SUnMapLS_IP_EBP_24 (KERNEL32.@)
686  */
687 __ASM_STDCALL_FUNC( SUnMapLS_IP_EBP_24, 0,
688                     "pushl %eax\n\t"  /* preserve eax */
689                     "pushl 24(%ebp)\n\t"
690                     "call " __ASM_NAME("UnMapLS") __ASM_STDCALL(4) "\n\t"
691                     "movl $0,24(%ebp)\n\t"
692                     "popl %eax\n\t"
693                     "ret" )
694
695 /***********************************************************************
696  *              SUnMapLS_IP_EBP_28 (KERNEL32.@)
697  */
698 __ASM_STDCALL_FUNC( SUnMapLS_IP_EBP_28, 0,
699                     "pushl %eax\n\t"  /* preserve eax */
700                     "pushl 28(%ebp)\n\t"
701                     "call " __ASM_NAME("UnMapLS") __ASM_STDCALL(4) "\n\t"
702                     "movl $0,28(%ebp)\n\t"
703                     "popl %eax\n\t"
704                     "ret" )
705
706 /***********************************************************************
707  *              SUnMapLS_IP_EBP_32 (KERNEL32.@)
708  */
709 __ASM_STDCALL_FUNC( SUnMapLS_IP_EBP_32, 0,
710                     "pushl %eax\n\t"  /* preserve eax */
711                     "pushl 32(%ebp)\n\t"
712                     "call " __ASM_NAME("UnMapLS") __ASM_STDCALL(4) "\n\t"
713                     "movl $0,32(%ebp)\n\t"
714                     "popl %eax\n\t"
715                     "ret" )
716
717 /***********************************************************************
718  *              SUnMapLS_IP_EBP_36 (KERNEL32.@)
719  */
720 __ASM_STDCALL_FUNC( SUnMapLS_IP_EBP_36, 0,
721                     "pushl %eax\n\t"  /* preserve eax */
722                     "pushl 36(%ebp)\n\t"
723                     "call " __ASM_NAME("UnMapLS") __ASM_STDCALL(4) "\n\t"
724                     "movl $0,36(%ebp)\n\t"
725                     "popl %eax\n\t"
726                     "ret" )
727
728 /***********************************************************************
729  *              SUnMapLS_IP_EBP_40 (KERNEL32.@)
730  */
731 __ASM_STDCALL_FUNC( SUnMapLS_IP_EBP_40, 0,
732                     "pushl %eax\n\t"  /* preserve eax */
733                     "pushl 40(%ebp)\n\t"
734                     "call " __ASM_NAME("UnMapLS") __ASM_STDCALL(4) "\n\t"
735                     "movl $0,40(%ebp)\n\t"
736                     "popl %eax\n\t"
737                     "ret" )