Alex Buell <alex.buell@munted.org.uk>:
[reactos.git] / reactos / lib / rtl / i386 / math_asm.S
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Run-Time Library
5 * FILE: lib/rtl/i386/math.S
6 * PROGRAMER: Alex Ionescu (alex@relsoft.net)
7 * Eric Kohl (ekohl@rz-online.de)
8 *
9 * Copyright (C) 2002 Michael Ringgaard.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the project nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES// LOSS OF USE, DATA, OR PROFITS// OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38 /* GLOBALS ****************************************************************/
39
40 .globl __ftol
41 .globl __aullshr
42 .globl __allrem
43 .globl __aulldiv
44 .globl __allshr
45 .globl __allshl
46 .globl __aullrem
47 .globl __allmul
48 .globl __alldiv
49 .globl __aulldvrm
50 .globl __alldvrm
51 .globl _atan
52 .globl _ceil
53 .globl _cos
54 .globl _fabs
55 .globl _floor
56 .globl _log
57 .globl _pow
58 .globl _sin
59 .globl _sqrt
60 .globl _tan
61 .globl __fltused
62
63 /* DATA ********************************************************************/
64
65 fzero:
66 .long 0 // Floating point zero
67 .long 0 // Floating point zero
68
69 __fltused:
70 .long 0x9875
71
72 .intel_syntax noprefix
73
74 /* FUNCTIONS ***************************************************************/
75
76 //
77 // lldiv - signed long divide
78 //
79 // Purpose:
80 // Does a signed long divide of the arguments. Arguments are
81 // not changed.
82 //
83 // Entry:
84 // Arguments are passed on the stack:
85 // 1st pushed: divisor (QWORD)
86 // 2nd pushed: dividend (QWORD)
87 //
88 // Exit:
89 // EDX:EAX contains the quotient (dividend/divisor)
90 // NOTE: this routine removes the parameters from the stack.
91 //
92 // Uses:
93 // ECX
94 //
95
96 __alldiv:
97
98 push edi
99 push esi
100 push ebx
101
102 // Set up the local stack and save the index registers. When this is done
103 // the stack frame will look as follows (assuming that the expression a/b will
104 // generate a call to lldiv(a, b)):
105 //
106 // -----------------
107 // | |
108 // |---------------|
109 // | |
110 // |--divisor (b)--|
111 // | |
112 // |---------------|
113 // | |
114 // |--dividend (a)-|
115 // | |
116 // |---------------|
117 // | return addr** |
118 // |---------------|
119 // | EDI |
120 // |---------------|
121 // | ESI |
122 // |---------------|
123 // ESP---->| EBX |
124 // -----------------
125 //
126
127 #define DVNDLO [esp + 16] // stack address of dividend (a)
128 #define DVNDHI [esp + 20] // stack address of dividend (a)
129 #define DVSRLO [esp + 24] // stack address of divisor (b)
130 #define DVSRHI [esp + 28] // stack address of divisor (b)
131
132 // Determine sign of the result (edi = 0 if result is positive, non-zero
133 // otherwise) and make operands positive.
134
135 xor edi,edi // result sign assumed positive
136
137 mov eax,DVNDHI // hi word of a
138 or eax,eax // test to see if signed
139 jge short L1 // skip rest if a is already positive
140 inc edi // complement result sign flag
141 mov edx,DVNDLO // lo word of a
142 neg eax // make a positive
143 neg edx
144 sbb eax,0
145 mov DVNDHI,eax // save positive value
146 mov DVNDLO,edx
147 L1:
148 mov eax,DVSRHI // hi word of b
149 or eax,eax // test to see if signed
150 jge short L2 // skip rest if b is already positive
151 inc edi // complement the result sign flag
152 mov edx,DVSRLO // lo word of a
153 neg eax // make b positive
154 neg edx
155 sbb eax,0
156 mov DVSRHI,eax // save positive value
157 mov DVSRLO,edx
158 L2:
159
160 //
161 // Now do the divide. First look to see if the divisor is less than 4194304K.
162 // If so, then we can use a simple algorithm with word divides, otherwise
163 // things get a little more complex.
164 //
165 // NOTE - eax currently contains the high order word of DVSR
166 //
167
168 or eax,eax // check to see if divisor < 4194304K
169 jnz short L3 // nope, gotta do this the hard way
170 mov ecx,DVSRLO // load divisor
171 mov eax,DVNDHI // load high word of dividend
172 xor edx,edx
173 div ecx // eax <- high order bits of quotient
174 mov ebx,eax // save high bits of quotient
175 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend
176 div ecx // eax <- low order bits of quotient
177 mov edx,ebx // edx:eax <- quotient
178 jmp short L4 // set sign, restore stack and return
179
180 //
181 // Here we do it the hard way. Remember, eax contains the high word of DVSR
182 //
183
184 L3:
185 mov ebx,eax // ebx:ecx <- divisor
186 mov ecx,DVSRLO
187 mov edx,DVNDHI // edx:eax <- dividend
188 mov eax,DVNDLO
189 L5:
190 shr ebx,1 // shift divisor right one bit
191 rcr ecx,1
192 shr edx,1 // shift dividend right one bit
193 rcr eax,1
194 or ebx,ebx
195 jnz short L5 // loop until divisor < 4194304K
196 div ecx // now divide, ignore remainder
197 mov esi,eax // save quotient
198
199 //
200 // We may be off by one, so to check, we will multiply the quotient
201 // by the divisor and check the result against the orignal dividend
202 // Note that we must also check for overflow, which can occur if the
203 // dividend is close to 2**64 and the quotient is off by 1.
204 //
205
206 mul dword ptr DVSRHI // QUOT * DVSRHI
207 mov ecx,eax
208 mov eax,DVSRLO
209 mul esi // QUOT * DVSRLO
210 add edx,ecx // EDX:EAX = QUOT * DVSR
211 jc short L6 // carry means Quotient is off by 1
212
213 //
214 // do long compare here between original dividend and the result of the
215 // multiply in edx:eax. If original is larger or equal, we are ok, otherwise
216 // subtract one (1) from the quotient.
217 //
218
219 cmp edx,DVNDHI // compare hi words of result and original
220 ja short L6 // if result > original, do subtract
221 jb short L7 // if result < original, we are ok
222 cmp eax,DVNDLO // hi words are equal, compare lo words
223 jbe short L7 // if less or equal we are ok, else subtract
224 L6:
225 dec esi // subtract 1 from quotient
226 L7:
227 xor edx,edx // edx:eax <- quotient
228 mov eax,esi
229
230 //
231 // Just the cleanup left to do. edx:eax contains the quotient. Set the sign
232 // according to the save value, cleanup the stack, and return.
233 //
234
235 L4:
236 dec edi // check to see if result is negative
237 jnz short L8 // if EDI == 0, result should be negative
238 neg edx // otherwise, negate the result
239 neg eax
240 sbb edx,0
241
242 //
243 // Restore the saved registers and return.
244 //
245
246 L8:
247 pop ebx
248 pop esi
249 pop edi
250
251 ret 16
252
253 //
254 // llmul - long multiply routine
255 //
256 // Purpose:
257 // Does a long multiply (same for signed/unsigned)
258 // Parameters are not changed.
259 //
260 // Entry:
261 // Parameters are passed on the stack:
262 // 1st pushed: multiplier (QWORD)
263 // 2nd pushed: multiplicand (QWORD)
264 //
265 // Exit:
266 // EDX:EAX - product of multiplier and multiplicand
267 // NOTE: parameters are removed from the stack
268 //
269 // Uses:
270 // ECX
271 //
272
273 __allmul:
274
275 #define ALO [esp + 4] // stack address of a
276 #define AHI [esp + 8] // stack address of a
277 #define BLO [esp + 12] // stack address of b
278 #define BHI [esp + 16] // stack address of b
279
280 //
281 // AHI, BHI : upper 32 bits of A and B
282 // ALO, BLO : lower 32 bits of A and B
283 //
284 // ALO * BLO
285 // ALO * BHI
286 // + BLO * AHI
287 // ---------------------
288 //
289
290 mov eax,AHI
291 mov ecx,BHI
292 or ecx,eax //test for both hiwords zero.
293 mov ecx,BLO
294 jnz short hard //both are zero, just mult ALO and BLO
295
296 mov eax,AHI
297 mul ecx
298
299 ret 16 // callee restores the stack
300
301 hard:
302 push ebx
303
304 // must redefine A and B since esp has been altered
305
306 #define A2LO [esp + 4] // stack address of a
307 #define A2HI [esp + 8] // stack address of a
308 #define B2LO [esp + 12] // stack address of b
309 #define B2HI [esp + 16] // stack address of b
310
311 mul ecx //eax has AHI, ecx has BLO, so AHI * BLO
312 mov ebx,eax //save result
313
314 mov eax,A2LO
315 mul dword ptr B2HI //ALO * BHI
316 add ebx,eax //ebx = ((ALO * BHI) + (AHI * BLO))
317
318 mov eax,A2LO //ecx = BLO
319 mul ecx //so edx:eax = ALO*BLO
320 add edx,ebx //now edx has all the LO*HI stuff
321
322 pop ebx
323
324 ret 16 // callee restores the stack
325
326 //
327 // llrem - signed long remainder
328 //
329 // Purpose:
330 // Does a signed long remainder of the arguments. Arguments are
331 // not changed.
332 //
333 // Entry:
334 // Arguments are passed on the stack:
335 // 1st pushed: divisor (QWORD)
336 // 2nd pushed: dividend (QWORD)
337 //
338 // Exit:
339 // EDX:EAX contains the remainder (dividend%divisor)
340 // NOTE: this routine removes the parameters from the stack.
341 //
342 // Uses:
343 // ECX
344 //
345
346 __allrem :
347
348 push ebx
349 push edi
350
351 // Set up the local stack and save the index registers. When this is done
352 // the stack frame will look as follows (assuming that the expression a%b will
353 // generate a call to lrem(a, b)):
354 //
355 // -----------------
356 // | |
357 // |---------------|
358 // | |
359 // |--divisor (b)--|
360 // | |
361 // |---------------|
362 // | |
363 // |--dividend (a)-|
364 // | |
365 // |---------------|
366 // | return addr** |
367 // |---------------|
368 // | EBX |
369 // |---------------|
370 // ESP---->| EDI |
371 // -----------------
372 //
373
374 #undef DVNDLO
375 #undef DVNDHI
376 #undef DVSRLO
377 #undef DVSRHI
378 #define DVNDLO [esp + 12] // stack address of dividend (a)
379 #define DVNDHI [esp + 16] // stack address of dividend (a)
380 #define DVSRLO [esp + 20] // stack address of divisor (b)
381 #define DVSRHI [esp + 24] // stack address of divisor (b)
382
383 // Determine sign of the result (edi = 0 if result is positive, non-zero
384 // otherwise) and make operands positive.
385
386 xor edi,edi // result sign assumed positive
387
388 mov eax,DVNDHI // hi word of a
389 or eax,eax // test to see if signed
390 jge short .L1 // skip rest if a is already positive
391 inc edi // complement result sign flag bit
392 mov edx,DVNDLO // lo word of a
393 neg eax // make a positive
394 neg edx
395 sbb eax,0
396 mov DVNDHI,eax // save positive value
397 mov DVNDLO,edx
398 .L1:
399 mov eax,DVSRHI // hi word of b
400 or eax,eax // test to see if signed
401 jge short .L2 // skip rest if b is already positive
402 mov edx,DVSRLO // lo word of b
403 neg eax // make b positive
404 neg edx
405 sbb eax,0
406 mov DVSRHI,eax // save positive value
407 mov DVSRLO,edx
408 .L2:
409
410 //
411 // Now do the divide. First look to see if the divisor is less than 4194304K.
412 // If so, then we can use a simple algorithm with word divides, otherwise
413 // things get a little more complex.
414 //
415 // NOTE - eax currently contains the high order word of DVSR
416 //
417
418 or eax,eax // check to see if divisor < 4194304K
419 jnz short .L3 // nope, gotta do this the hard way
420 mov ecx,DVSRLO // load divisor
421 mov eax,DVNDHI // load high word of dividend
422 xor edx,edx
423 div ecx // edx <- remainder
424 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend
425 div ecx // edx <- final remainder
426 mov eax,edx // edx:eax <- remainder
427 xor edx,edx
428 dec edi // check result sign flag
429 jns short .L4 // negate result, restore stack and return
430 jmp short .L8 // result sign ok, restore stack and return
431
432 //
433 // Here we do it the hard way. Remember, eax contains the high word of DVSR
434 //
435
436 .L3:
437 mov ebx,eax // ebx:ecx <- divisor
438 mov ecx,DVSRLO
439 mov edx,DVNDHI // edx:eax <- dividend
440 mov eax,DVNDLO
441 .L5:
442 shr ebx,1 // shift divisor right one bit
443 rcr ecx,1
444 shr edx,1 // shift dividend right one bit
445 rcr eax,1
446 or ebx,ebx
447 jnz short .L5 // loop until divisor < 4194304K
448 div ecx // now divide, ignore remainder
449
450 //
451 // We may be off by one, so to check, we will multiply the quotient
452 // by the divisor and check the result against the orignal dividend
453 // Note that we must also check for overflow, which can occur if the
454 // dividend is close to 2**64 and the quotient is off by 1.
455 //
456
457 mov ecx,eax // save a copy of quotient in ECX
458 mul dword ptr DVSRHI
459 xchg ecx,eax // save product, get quotient in EAX
460 mul dword ptr DVSRLO
461 add edx,ecx // EDX:EAX = QUOT * DVSR
462 jc short .L6 // carry means Quotient is off by 1
463
464 //
465 // do long compare here between original dividend and the result of the
466 // multiply in edx:eax. If original is larger or equal, we are ok, otherwise
467 // subtract the original divisor from the result.
468 //
469
470 cmp edx,DVNDHI // compare hi words of result and original
471 ja short .L6 // if result > original, do subtract
472 jb short .L7 // if result < original, we are ok
473 cmp eax,DVNDLO // hi words are equal, compare lo words
474 jbe short .L7 // if less or equal we are ok, else subtract
475 .L6:
476 sub eax,DVSRLO // subtract divisor from result
477 sbb edx,DVSRHI
478 .L7:
479
480 //
481 // Calculate remainder by subtracting the result from the original dividend.
482 // Since the result is already in a register, we will do the subtract in the
483 // opposite direction and negate the result if necessary.
484 //
485
486 sub eax,DVNDLO // subtract dividend from result
487 sbb edx,DVNDHI
488
489 //
490 // Now check the result sign flag to see if the result is supposed to be positive
491 // or negative. It is currently negated (because we subtracted in the 'wrong'
492 // direction), so if the sign flag is set we are done, otherwise we must negate
493 // the result to make it positive again.
494 //
495
496 dec edi // check result sign flag
497 jns short .L8 // result is ok, restore stack and return
498 .L4:
499 neg edx // otherwise, negate the result
500 neg eax
501 sbb edx,0
502
503 //
504 // Just the cleanup left to do. edx:eax contains the quotient.
505 // Restore the saved registers and return.
506 //
507
508 .L8:
509 pop edi
510 pop ebx
511
512 ret 16
513
514 //
515 // llshl - long shift left
516 //
517 // Purpose:
518 // Does a Long Shift Left (signed and unsigned are identical)
519 // Shifts a long left any number of bits.
520 //
521 // Entry:
522 // EDX:EAX - long value to be shifted
523 // CL - number of bits to shift by
524 //
525 // Exit:
526 // EDX:EAX - shifted value
527 //
528 // Uses:
529 // CL is destroyed.
530 //
531
532 __allshl:
533
534 //
535 // Handle shifts of 64 or more bits (all get 0)
536 //
537 cmp cl, 64
538 jae short RETZERO
539
540 //
541 // Handle shifts of between 0 and 31 bits
542 //
543 cmp cl, 32
544 jae short MORE32
545 shld edx,eax,cl
546 shl eax,cl
547 ret
548
549 //
550 // Handle shifts of between 32 and 63 bits
551 //
552 MORE32:
553 mov edx,eax
554 xor eax,eax
555 and cl,31
556 shl edx,cl
557 ret
558
559 //
560 // return 0 in edx:eax
561 //
562 RETZERO:
563 xor eax,eax
564 xor edx,edx
565 ret
566
567 //
568 // llshr - long shift right
569 //
570 // Purpose:
571 // Does a signed Long Shift Right
572 // Shifts a long right any number of bits.
573 //
574 // Entry:
575 // EDX:EAX - long value to be shifted
576 // CL - number of bits to shift by
577 //
578 // Exit:
579 // EDX:EAX - shifted value
580 //
581 // Uses:
582 // CL is destroyed.
583 //
584
585 __allshr:
586
587 //
588 // Handle shifts of 64 bits or more (if shifting 64 bits or more, the result
589 // depends only on the high order bit of edx).
590 //
591 cmp cl,64
592 jae short .RETSIGN
593
594 //
595 // Handle shifts of between 0 and 31 bits
596 //
597 cmp cl, 32
598 jae short .MORE32
599 shrd eax,edx,cl
600 sar edx,cl
601 ret
602
603 //
604 // Handle shifts of between 32 and 63 bits
605 //
606 .MORE32:
607 mov eax,edx
608 sar edx,31
609 and cl,31
610 sar eax,cl
611 ret
612
613 //
614 // Return double precision 0 or -1, depending on the sign of edx
615 //
616 .RETSIGN:
617 sar edx,31
618 mov eax,edx
619 ret
620
621 //
622 // ulldiv - unsigned long divide
623 //
624 // Purpose:
625 // Does a unsigned long divide of the arguments. Arguments are
626 // not changed.
627 //
628 // Entry:
629 // Arguments are passed on the stack:
630 // 1st pushed: divisor (QWORD)
631 // 2nd pushed: dividend (QWORD)
632 //
633 // Exit:
634 // EDX:EAX contains the quotient (dividend/divisor)
635 // NOTE: this routine removes the parameters from the stack.
636 //
637 // Uses:
638 // ECX
639 //
640
641 __aulldiv:
642
643 push ebx
644 push esi
645
646 // Set up the local stack and save the index registers. When this is done
647 // the stack frame will look as follows (assuming that the expression a/b will
648 // generate a call to uldiv(a, b)):
649 //
650 // -----------------
651 // | |
652 // |---------------|
653 // | |
654 // |--divisor (b)--|
655 // | |
656 // |---------------|
657 // | |
658 // |--dividend (a)-|
659 // | |
660 // |---------------|
661 // | return addr** |
662 // |---------------|
663 // | EBX |
664 // |---------------|
665 // ESP---->| ESI |
666 // -----------------
667 //
668
669 #undef DVNDLO
670 #undef DVNDHI
671 #undef DVSRLO
672 #undef DVSRHI
673 #define DVNDLO [esp + 12] // stack address of dividend (a)
674 #define DVNDHI [esp + 16] // stack address of dividend (a)
675 #define DVSRLO [esp + 20] // stack address of divisor (b)
676 #define DVSRHI [esp + 24] // stack address of divisor (b)
677
678 //
679 // Now do the divide. First look to see if the divisor is less than 4194304K.
680 // If so, then we can use a simple algorithm with word divides, otherwise
681 // things get a little more complex.
682 //
683
684 mov eax,DVSRHI // check to see if divisor < 4194304K
685 or eax,eax
686 jnz short ..L1 // nope, gotta do this the hard way
687 mov ecx,DVSRLO // load divisor
688 mov eax,DVNDHI // load high word of dividend
689 xor edx,edx
690 div ecx // get high order bits of quotient
691 mov ebx,eax // save high bits of quotient
692 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend
693 div ecx // get low order bits of quotient
694 mov edx,ebx // edx:eax <- quotient hi:quotient lo
695 jmp short ..L2 // restore stack and return
696
697 //
698 // Here we do it the hard way. Remember, eax contains DVSRHI
699 //
700
701 ..L1:
702 mov ecx,eax // ecx:ebx <- divisor
703 mov ebx,DVSRLO
704 mov edx,DVNDHI // edx:eax <- dividend
705 mov eax,DVNDLO
706 ..L3:
707 shr ecx,1 // shift divisor right one bit// hi bit <- 0
708 rcr ebx,1
709 shr edx,1 // shift dividend right one bit// hi bit <- 0
710 rcr eax,1
711 or ecx,ecx
712 jnz short ..L3 // loop until divisor < 4194304K
713 div ebx // now divide, ignore remainder
714 mov esi,eax // save quotient
715
716 //
717 // We may be off by one, so to check, we will multiply the quotient
718 // by the divisor and check the result against the orignal dividend
719 // Note that we must also check for overflow, which can occur if the
720 // dividend is close to 2**64 and the quotient is off by 1.
721 //
722
723 mul dword ptr DVSRHI // QUOT * DVSRHI
724 mov ecx,eax
725 mov eax,DVSRLO
726 mul esi // QUOT * DVSRLO
727 add edx,ecx // EDX:EAX = QUOT * DVSR
728 jc short ..L4 // carry means Quotient is off by 1
729
730 //
731 // do long compare here between original dividend and the result of the
732 // multiply in edx:eax. If original is larger or equal, we are ok, otherwise
733 // subtract one (1) from the quotient.
734 //
735
736 cmp edx,DVNDHI // compare hi words of result and original
737 ja short ..L4 // if result > original, do subtract
738 jb short ..L5 // if result < original, we are ok
739 cmp eax,DVNDLO // hi words are equal, compare lo words
740 jbe short ..L5 // if less or equal we are ok, else subtract
741 ..L4:
742 dec esi // subtract 1 from quotient
743 ..L5:
744 xor edx,edx // edx:eax <- quotient
745 mov eax,esi
746
747 //
748 // Just the cleanup left to do. edx:eax contains the quotient.
749 // Restore the saved registers and return.
750 //
751
752 ..L2:
753
754 pop esi
755 pop ebx
756
757 ret 16
758
759 //
760 // ullshr - long shift right
761 //
762 // Purpose:
763 // Does a unsigned Long Shift Right
764 // Shifts a long right any number of bits.
765 //
766 // Entry:
767 // EDX:EAX - long value to be shifted
768 // CL - number of bits to shift by
769 //
770 // Exit:
771 // EDX:EAX - shifted value
772 //
773 // Uses:
774 // CL is destroyed.
775 //
776
777 __aullshr:
778
779 //
780 // Handle shifts of 64 bits or more (if shifting 64 bits or more, the result
781 // depends only on the high order bit of edx).
782 //
783 cmp cl,64
784 jae short ..RETZERO
785
786 //
787 // Handle shifts of between 0 and 31 bits
788 //
789 cmp cl, 32
790 jae short ..MORE32
791 shrd eax,edx,cl
792 shr edx,cl
793 ret
794
795 //
796 // Handle shifts of between 32 and 63 bits
797 //
798 ..MORE32:
799 mov eax,edx
800 xor edx,edx
801 and cl,31
802 shr eax,cl
803 ret
804
805 //
806 // return 0 in edx:eax
807 //
808 ..RETZERO:
809 xor eax,eax
810 xor edx,edx
811 ret
812
813 //
814 // ullrem - unsigned long remainder
815 //
816 // Purpose:
817 // Does a unsigned long remainder of the arguments. Arguments are
818 // not changed.
819 //
820 // Entry:
821 // Arguments are passed on the stack:
822 // 1st pushed: divisor (QWORD)
823 // 2nd pushed: dividend (QWORD)
824 //
825 // Exit:
826 // EDX:EAX contains the remainder (dividend%divisor)
827 // NOTE: this routine removes the parameters from the stack.
828 //
829 // Uses:
830 // ECX
831 //
832
833 __aullrem:
834
835 push ebx
836
837 // Set up the local stack and save the index registers. When this is done
838 // the stack frame will look as follows (assuming that the expression a%b will
839 // generate a call to ullrem(a, b)):
840 //
841 // -----------------
842 // | |
843 // |---------------|
844 // | |
845 // |--divisor (b)--|
846 // | |
847 // |---------------|
848 // | |
849 // |--dividend (a)-|
850 // | |
851 // |---------------|
852 // | return addr** |
853 // |---------------|
854 // ESP---->| EBX |
855 // -----------------
856 //
857
858 #undef DVNDLO
859 #undef DVNDHI
860 #undef DVSRLO
861 #undef DVSRHI
862 #define DVNDLO [esp + 8] // stack address of dividend (a)
863 #define DVNDHI [esp + 8] // stack address of dividend (a)
864 #define DVSRLO [esp + 16] // stack address of divisor (b)
865 #define DVSRHI [esp + 20] // stack address of divisor (b)
866
867 // Now do the divide. First look to see if the divisor is less than 4194304K.
868 // If so, then we can use a simple algorithm with word divides, otherwise
869 // things get a little more complex.
870 //
871
872 mov eax,DVSRHI // check to see if divisor < 4194304K
873 or eax,eax
874 jnz short ...L1 // nope, gotta do this the hard way
875 mov ecx,DVSRLO // load divisor
876 mov eax,DVNDHI // load high word of dividend
877 xor edx,edx
878 div ecx // edx <- remainder, eax <- quotient
879 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend
880 div ecx // edx <- final remainder
881 mov eax,edx // edx:eax <- remainder
882 xor edx,edx
883 jmp short ...L2 // restore stack and return
884
885 //
886 // Here we do it the hard way. Remember, eax contains DVSRHI
887 //
888
889 ...L1:
890 mov ecx,eax // ecx:ebx <- divisor
891 mov ebx,DVSRLO
892 mov edx,DVNDHI // edx:eax <- dividend
893 mov eax,DVNDLO
894 ...L3:
895 shr ecx,1 // shift divisor right one bit// hi bit <- 0
896 rcr ebx,1
897 shr edx,1 // shift dividend right one bit// hi bit <- 0
898 rcr eax,1
899 or ecx,ecx
900 jnz short ...L3 // loop until divisor < 4194304K
901 div ebx // now divide, ignore remainder
902
903 //
904 // We may be off by one, so to check, we will multiply the quotient
905 // by the divisor and check the result against the orignal dividend
906 // Note that we must also check for overflow, which can occur if the
907 // dividend is close to 2**64 and the quotient is off by 1.
908 //
909
910 mov ecx,eax // save a copy of quotient in ECX
911 mul dword ptr DVSRHI
912 xchg ecx,eax // put partial product in ECX, get quotient in EAX
913 mul dword ptr DVSRLO
914 add edx,ecx // EDX:EAX = QUOT * DVSR
915 jc short ...L4 // carry means Quotient is off by 1
916
917 //
918 // do long compare here between original dividend and the result of the
919 // multiply in edx:eax. If original is larger or equal, we're ok, otherwise
920 // subtract the original divisor from the result.
921 //
922
923 cmp edx,DVNDHI // compare hi words of result and original
924 ja short ...L4 // if result > original, do subtract
925 jb short ...L5 // if result < original, we're ok
926 cmp eax,DVNDLO // hi words are equal, compare lo words
927 jbe short ...L5 // if less or equal we're ok, else subtract
928 ...L4:
929 sub eax,DVSRLO // subtract divisor from result
930 sbb edx,DVSRHI
931 ...L5:
932
933 //
934 // Calculate remainder by subtracting the result from the original dividend.
935 // Since the result is already in a register, we will perform the subtract in
936 // the opposite direction and negate the result to make it positive.
937 //
938
939 sub eax,DVNDLO // subtract original dividend from result
940 sbb edx,DVNDHI
941 neg edx // and negate it
942 neg eax
943 sbb edx,0
944
945 //
946 // Just the cleanup left to do. dx:ax contains the remainder.
947 // Restore the saved registers and return.
948 //
949
950 ...L2:
951
952 pop ebx
953
954 ret 16
955
956
957 /*
958 * This routine is called by MSVC-generated code to convert from floating point
959 * to integer representation. The floating point number to be converted is
960 * on the top of the floating point stack.
961 */
962 __ftol:
963 /* Set up stack frame */
964 push ebp
965 mov ebp, esp
966
967 /* Set "round towards zero" mode */
968 fstcw [ebp-2]
969 wait
970 mov ax, [ebp-2]
971 or ah, 0xC
972 mov [ebp-4], ax
973 fldcw [ebp-4]
974
975 /* Do the conversion */
976 fistp qword ptr [ebp-12]
977
978 /* Restore rounding mode */
979 fldcw [ebp-2]
980
981 /* Return value */
982 mov eax, [ebp-12]
983 mov edx, [ebp-8]
984
985 /* Remove stack frame and return*/
986 leave
987 ret
988
989 __alldvrm:
990 push edi
991 push esi
992 push ebp
993
994 // Set up the local stack and save the index registers. When this is done
995 // the stack frame will look as follows (assuming that the expression a/b will
996 // generate a call to alldvrm(a, b)):
997 //
998 // -----------------
999 // | |
1000 // |---------------|
1001 // | |
1002 // |--divisor (b)--|
1003 // | |
1004 // |---------------|
1005 // | |
1006 // |--dividend (a)-|
1007 // | |
1008 // |---------------|
1009 // | return addr** |
1010 // |---------------|
1011 // | EDI |
1012 // |---------------|
1013 // | ESI |
1014 // |---------------|
1015 // ESP---->| EBP |
1016 // -----------------
1017 //
1018
1019 #undef DVNDLO
1020 #undef DVNDHI
1021 #undef DVSRLO
1022 #undef DVSRHI
1023 #define DVNDLO [esp + 16] // stack address of dividend (a)
1024 #define DVNDHI [esp + 20] // stack address of dividend (a)
1025 #define DVSRLO [esp + 24] // stack address of divisor (b)
1026 #define DVSRHI [esp + 28] // stack address of divisor (b)
1027
1028 // Determine sign of the quotient (edi = 0 if result is positive, non-zero
1029 // otherwise) and make operands positive.
1030 // Sign of the remainder is kept in ebp.
1031
1032 xor edi,edi // result sign assumed positive
1033 xor ebp,ebp // result sign assumed positive
1034
1035 mov eax,DVNDHI // hi word of a
1036 or eax,eax // test to see if signed
1037 jge short ....L1 // skip rest if a is already positive
1038 inc edi // complement result sign flag
1039 inc ebp // complement result sign flag
1040 mov edx,DVNDLO // lo word of a
1041 neg eax // make a positive
1042 neg edx
1043 sbb eax,0
1044 mov DVNDHI,eax // save positive value
1045 mov DVNDLO,edx
1046 ....L1:
1047 mov eax,DVSRHI // hi word of b
1048 or eax,eax // test to see if signed
1049 jge short ....L2 // skip rest if b is already positive
1050 inc edi // complement the result sign flag
1051 mov edx,DVSRLO // lo word of a
1052 neg eax // make b positive
1053 neg edx
1054 sbb eax,0
1055 mov DVSRHI,eax // save positive value
1056 mov DVSRLO,edx
1057 ....L2:
1058
1059 //
1060 // Now do the divide. First look to see if the divisor is less than 4194304K.
1061 // If so, then we can use a simple algorithm with word divides, otherwise
1062 // things get a little more complex.
1063 //
1064 // NOTE - eax currently contains the high order word of DVSR
1065 //
1066
1067 or eax,eax // check to see if divisor < 4194304K
1068 jnz short ....L3 // nope, gotta do this the hard way
1069 mov ecx,DVSRLO // load divisor
1070 mov eax,DVNDHI // load high word of dividend
1071 xor edx,edx
1072 div ecx // eax <- high order bits of quotient
1073 mov ebx,eax // save high bits of quotient
1074 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend
1075 div ecx // eax <- low order bits of quotient
1076 mov esi,eax // ebx:esi <- quotient
1077 //
1078 // Now we need to do a multiply so that we can compute the remainder.
1079 //
1080 mov eax,ebx // set up high word of quotient
1081 mul dword ptr DVSRLO // HIWORD(QUOT) * DVSR
1082 mov ecx,eax // save the result in ecx
1083 mov eax,esi // set up low word of quotient
1084 mul dword ptr DVSRLO // LOWORD(QUOT) * DVSR
1085 add edx,ecx // EDX:EAX = QUOT * DVSR
1086 jmp short ....L4 // complete remainder calculation
1087
1088 //
1089 // Here we do it the hard way. Remember, eax contains the high word of DVSR
1090 //
1091
1092 ....L3:
1093 mov ebx,eax // ebx:ecx <- divisor
1094 mov ecx,DVSRLO
1095 mov edx,DVNDHI // edx:eax <- dividend
1096 mov eax,DVNDLO
1097 ....L5:
1098 shr ebx,1 // shift divisor right one bit
1099 rcr ecx,1
1100 shr edx,1 // shift dividend right one bit
1101 rcr eax,1
1102 or ebx,ebx
1103 jnz short ....L5 // loop until divisor < 4194304K
1104 div ecx // now divide, ignore remainder
1105 mov esi,eax // save quotient
1106
1107 //
1108 // We may be off by one, so to check, we will multiply the quotient
1109 // by the divisor and check the result against the orignal dividend
1110 // Note that we must also check for overflow, which can occur if the
1111 // dividend is close to 2**64 and the quotient is off by 1.
1112 //
1113
1114 mul dword ptr DVSRHI // QUOT * DVSRHI
1115 mov ecx,eax
1116 mov eax,DVSRLO
1117 mul esi // QUOT * DVSRLO
1118 add edx,ecx // EDX:EAX = QUOT * DVSR
1119 jc short ....L6 // carry means Quotient is off by 1
1120
1121 //
1122 // do long compare here between original dividend and the result of the
1123 // multiply in edx:eax. If original is larger or equal, we are ok, otherwise
1124 // subtract one (1) from the quotient.
1125 //
1126
1127 cmp edx,DVNDHI // compare hi words of result and original
1128 ja short ....L6 // if result > original, do subtract
1129 jb short ....L7 // if result < original, we are ok
1130 cmp eax,DVNDLO // hi words are equal, compare lo words
1131 jbe short ....L7 // if less or equal we are ok, else subtract
1132 ....L6:
1133 dec esi // subtract 1 from quotient
1134 sub eax,DVSRLO // subtract divisor from result
1135 sbb edx,DVSRHI
1136 ....L7:
1137 xor ebx,ebx // ebx:esi <- quotient
1138
1139 ....L4:
1140 //
1141 // Calculate remainder by subtracting the result from the original dividend.
1142 // Since the result is already in a register, we will do the subtract in the
1143 // opposite direction and negate the result if necessary.
1144 //
1145
1146 sub eax,DVNDLO // subtract dividend from result
1147 sbb edx,DVNDHI
1148
1149 //
1150 // Now check the result sign flag to see if the result is supposed to be positive
1151 // or negative. It is currently negated (because we subtracted in the 'wrong'
1152 // direction), so if the sign flag is set we are done, otherwise we must negate
1153 // the result to make it positive again.
1154 //
1155
1156 dec ebp // check result sign flag
1157 jns short ....L9 // result is ok, set up the quotient
1158 neg edx // otherwise, negate the result
1159 neg eax
1160 sbb edx,0
1161
1162 //
1163 // Now we need to get the quotient into edx:eax and the remainder into ebx:ecx.
1164 //
1165 ....L9:
1166 mov ecx,edx
1167 mov edx,ebx
1168 mov ebx,ecx
1169 mov ecx,eax
1170 mov eax,esi
1171
1172 //
1173 // Just the cleanup left to do. edx:eax contains the quotient. Set the sign
1174 // according to the save value, cleanup the stack, and return.
1175 //
1176
1177 dec edi // check to see if result is negative
1178 jnz short ....L8 // if EDI == 0, result should be negative
1179 neg edx // otherwise, negate the result
1180 neg eax
1181 sbb edx,0
1182
1183 //
1184 // Restore the saved registers and return.
1185 //
1186
1187 ....L8:
1188 pop ebp
1189 pop esi
1190 pop edi
1191
1192 ret 16
1193
1194 __aulldvrm:
1195
1196 // ulldvrm - unsigned long divide and remainder
1197 //
1198 // Purpose:
1199 // Does a unsigned long divide and remainder of the arguments. Arguments
1200 // are not changed.
1201 //
1202 // Entry:
1203 // Arguments are passed on the stack:
1204 // 1st pushed: divisor (QWORD)
1205 // 2nd pushed: dividend (QWORD)
1206 //
1207 // Exit:
1208 // EDX:EAX contains the quotient (dividend/divisor)
1209 // EBX:ECX contains the remainder (divided % divisor)
1210 // NOTE: this routine removes the parameters from the stack.
1211 //
1212 // Uses:
1213 // ECX
1214 //
1215 push esi
1216
1217 // Set up the local stack and save the index registers. When this is done
1218 // the stack frame will look as follows (assuming that the expression a/b will
1219 // generate a call to aulldvrm(a, b)):
1220 //
1221 // -----------------
1222 // | |
1223 // |---------------|
1224 // | |
1225 // |--divisor (b)--|
1226 // | |
1227 // |---------------|
1228 // | |
1229 // |--dividend (a)-|
1230 // | |
1231 // |---------------|
1232 // | return addr** |
1233 // |---------------|
1234 // ESP---->| ESI |
1235 // -----------------
1236 //
1237
1238 #undef DVNDLO
1239 #undef DVNDHI
1240 #undef DVSRLO
1241 #undef DVSRHI
1242 #define DVNDLO [esp + 8] // stack address of dividend (a)
1243 #define DVNDHI [esp + 8] // stack address of dividend (a)
1244 #define DVSRLO [esp + 16] // stack address of divisor (b)
1245 #define DVSRHI [esp + 20] // stack address of divisor (b)
1246
1247 //
1248 // Now do the divide. First look to see if the divisor is less than 4194304K.
1249 // If so, then we can use a simple algorithm with word divides, otherwise
1250 // things get a little more complex.
1251 //
1252
1253 mov eax,DVSRHI // check to see if divisor < 4194304K
1254 or eax,eax
1255 jnz short .....L1 // nope, gotta do this the hard way
1256 mov ecx,DVSRLO // load divisor
1257 mov eax,DVNDHI // load high word of dividend
1258 xor edx,edx
1259 div ecx // get high order bits of quotient
1260 mov ebx,eax // save high bits of quotient
1261 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend
1262 div ecx // get low order bits of quotient
1263 mov esi,eax // ebx:esi <- quotient
1264
1265 //
1266 // Now we need to do a multiply so that we can compute the remainder.
1267 //
1268 mov eax,ebx // set up high word of quotient
1269 mul dword ptr DVSRLO // HIWORD(QUOT) * DVSR
1270 mov ecx,eax // save the result in ecx
1271 mov eax,esi // set up low word of quotient
1272 mul dword ptr DVSRLO // LOWORD(QUOT) * DVSR
1273 add edx,ecx // EDX:EAX = QUOT * DVSR
1274 jmp short .....L2 // complete remainder calculation
1275
1276 //
1277 // Here we do it the hard way. Remember, eax contains DVSRHI
1278 //
1279
1280 .....L1:
1281 mov ecx,eax // ecx:ebx <- divisor
1282 mov ebx,DVSRLO
1283 mov edx,DVNDHI // edx:eax <- dividend
1284 mov eax,DVNDLO
1285 .....L3:
1286 shr ecx,1 // shift divisor right one bit// hi bit <- 0
1287 rcr ebx,1
1288 shr edx,1 // shift dividend right one bit// hi bit <- 0
1289 rcr eax,1
1290 or ecx,ecx
1291 jnz short .....L3 // loop until divisor < 4194304K
1292 div ebx // now divide, ignore remainder
1293 mov esi,eax // save quotient
1294
1295 //
1296 // We may be off by one, so to check, we will multiply the quotient
1297 // by the divisor and check the result against the orignal dividend
1298 // Note that we must also check for overflow, which can occur if the
1299 // dividend is close to 2**64 and the quotient is off by 1.
1300 //
1301
1302 mul dword ptr DVSRHI // QUOT * DVSRHI
1303 mov ecx,eax
1304 mov eax,DVSRLO
1305 mul esi // QUOT * DVSRLO
1306 add edx,ecx // EDX:EAX = QUOT * DVSR
1307 jc short .....L4 // carry means Quotient is off by 1
1308
1309 //
1310 // do long compare here between original dividend and the result of the
1311 // multiply in edx:eax. If original is larger or equal, we are ok, otherwise
1312 // subtract one (1) from the quotient.
1313 //
1314
1315 cmp edx,DVNDHI // compare hi words of result and original
1316 ja short .....L4 // if result > original, do subtract
1317 jb short .....L5 // if result < original, we are ok
1318 cmp eax,DVNDLO // hi words are equal, compare lo words
1319 jbe short .....L5 // if less or equal we are ok, else subtract
1320 .....L4:
1321 dec esi // subtract 1 from quotient
1322 sub eax,DVSRLO // subtract divisor from result
1323 sbb edx,DVSRHI
1324 .....L5:
1325 xor ebx,ebx // ebx:esi <- quotient
1326
1327 .....L2:
1328 //
1329 // Calculate remainder by subtracting the result from the original dividend.
1330 // Since the result is already in a register, we will do the subtract in the
1331 // opposite direction and negate the result.
1332 //
1333
1334 sub eax,DVNDLO // subtract dividend from result
1335 sbb edx,DVNDHI
1336 neg edx // otherwise, negate the result
1337 neg eax
1338 sbb edx,0
1339
1340 //
1341 // Now we need to get the quotient into edx:eax and the remainder into ebx:ecx.
1342 //
1343 mov ecx,edx
1344 mov edx,ebx
1345 mov ebx,ecx
1346 mov ecx,eax
1347 mov eax,esi
1348 //
1349 // Just the cleanup left to do. edx:eax contains the quotient.
1350 // Restore the saved registers and return.
1351 //
1352
1353 pop esi
1354
1355 ret 16
1356
1357 _atan:
1358 push ebp
1359 mov ebp,esp
1360 fld qword ptr [ebp+8] // Load real from stack
1361 fld1 // Load constant 1
1362 fpatan // Take the arctangent
1363 pop ebp
1364 ret
1365
1366 _ceil:
1367 push ebp
1368 mov ebp,esp
1369 sub esp,4 // Allocate temporary space
1370 fld qword ptr [ebp+8] // Load real from stack
1371 fstcw [ebp-2] // Save control word
1372 fclex // Clear exceptions
1373 mov word ptr [ebp-4],0xb63 // Rounding control word
1374 fldcw [ebp-4] // Set new rounding control
1375 frndint // Round to integer
1376 fclex // Clear exceptions
1377 fldcw [ebp-2] // Restore control word
1378 mov esp,ebp // Deallocate temporary space
1379 pop ebp
1380 ret
1381
1382 _cos:
1383 push ebp
1384 mov ebp,esp // Point to the stack frame
1385 fld qword ptr [ebp+8] // Load real from stack
1386 fcos // Take the cosine
1387 pop ebp
1388 ret
1389
1390 _fabs:
1391 push ebp
1392 mov ebp,esp
1393 fld qword ptr [ebp+8] // Load real from stack
1394 fabs // Take the absolute value
1395 pop ebp
1396 ret
1397
1398 _floor:
1399 push ebp
1400 mov ebp,esp
1401 sub esp,4 // Allocate temporary space
1402 fld qword ptr [ebp+8] // Load real from stack
1403 fstcw [ebp-2] // Save control word
1404 fclex // Clear exceptions
1405 mov word ptr [ebp-4],0x763 // Rounding control word
1406 fldcw [ebp-4] // Set new rounding control
1407 frndint // Round to integer
1408 fclex // Clear exceptions
1409 fldcw [ebp-2] // Restore control word
1410 mov esp,ebp
1411 pop ebp
1412 ret
1413
1414 _log:
1415 push ebp
1416 mov ebp,esp
1417 fld qword ptr [ebp+8] // Load real from stack
1418 fldln2 // Load log base e of 2
1419 fxch st(1) // Exchange st, st(1)
1420 fyl2x // Compute the natural log(x)
1421 pop ebp
1422 ret
1423
1424 _pow:
1425 push ebp
1426 mov ebp,esp
1427 sub esp,12 // Allocate temporary space
1428 push edi // Save register edi
1429 push eax // Save register eax
1430 mov dword ptr [ebp-12],0 // Set negation flag to zero
1431 fld qword ptr [ebp+16] // Load real from stack
1432 fld qword ptr [ebp+8] // Load real from stack
1433 mov edi,offset flat:fzero // Point to real zero
1434 fcom qword ptr [edi] // Compare x with zero
1435 fstsw ax // Get the FPU status word
1436 mov al,ah // Move condition flags to AL
1437 lahf // Load Flags into AH
1438 and al, 0b01000101 // Isolate C0, C2 and C3
1439 and ah, 0b10111010 // Turn off CF, PF and ZF
1440 or ah,al // Set new CF, PF and ZF
1441 sahf // Store AH into Flags
1442 jb __fpow1 // Re-direct if x < 0
1443 ja __fpow3 // Re-direct if x > 0
1444 fxch // Swap st, st(1)
1445 fcom qword ptr [edi] // Compare y with zero
1446 fxch // Restore x as top of stack
1447 fstsw ax // Get the FPU status word
1448 mov al,ah // Move condition flags to AL
1449 lahf // Load Flags into AH
1450 and al, 0b01000101 // Isolate C0, C2 and C3
1451 and ah, 0b10111010 // Turn off CF, PF and ZF
1452 or ah,al // Set new CF, PF and ZF
1453 sahf // Store AH into Flags
1454 ja __fpow3 // Re-direct if y > 0
1455 fstp st(1) // Set new stack top and pop
1456 mov eax,1 // Set domain error (EDOM)
1457 jmp __fpow5 // End of case
1458 __fpow1: fxch // Put y on top of stack
1459 fld st // Duplicate y as st(1)
1460 frndint // Round to integer
1461 fxch // Put y on top of stack
1462 fcomp // y = int(y) ?
1463 fstsw ax // Get the FPU status word
1464 mov al,ah // Move condition flags to AL
1465 lahf // Load Flags into AH
1466 and al, 0b01000101 // Isolate C0, C2 and C3
1467 and ah, 0b10111010 // Turn off CF, PF and ZF
1468 or ah,al // Set new CF, PF and ZF
1469 sahf // Store AH into Flags
1470 je __fpow2 // Proceed if y = int(y)
1471 fstp st(1) // Set new stack top and pop
1472 fldz // Set result to zero
1473 fstp st(1) // Set new stack top and pop
1474 mov eax,1 // Set domain error (EDOM)
1475 jmp __fpow5 // End of case
1476 __fpow2: fist dword ptr [ebp-12] // Store y as integer
1477 and dword ptr [ebp-12],1 // Set bit if y is odd
1478 fxch // Put x on top of stack
1479 fabs // x = |x|
1480 __fpow3: fldln2 // Load log base e of 2
1481 fxch st(1) // Exchange st, st(1)
1482 fyl2x // Compute the natural log(x)
1483 fmulp // Compute y * ln(x)
1484 fldl2e // Load log base 2(e)
1485 fmulp st(1),st // Multiply x * log base 2(e)
1486 fst st(1) // Push result
1487 frndint // Round to integer
1488 fsub st(1),st // Subtract
1489 fxch // Exchange st, st(1)
1490 f2xm1 // Compute 2 to the (x - 1)
1491 fld1 // Load real number 1
1492 faddp // 2 to the x
1493 fscale // Scale by power of 2
1494 fstp st(1) // Set new stack top and pop
1495 test dword ptr [ebp-12],1 // Negation required ?
1496 jz __fpow4 // No, re-direct
1497 fchs // Negate the result
1498 __fpow4: fstp qword ptr [ebp-8] // Save (double)pow(x, y)
1499 fld qword ptr [ebp-8] // Load (double)pow(x, y)
1500 fxam // Examine st
1501 fstsw ax // Get the FPU status word
1502 cmp ah,5 // Infinity ?
1503 jne __fpow6 // No, end of case
1504 mov eax,2 // Set range error (ERANGE)
1505 // Get errno pointer offset
1506 __fpow5: int 3
1507 mov edi,0 // TODO: offset flat:__crt_errno
1508 mov edi,[edi] // Get C errno variable pointer
1509 mov dword ptr [edi],eax // Set errno
1510 __fpow6: pop eax // Restore register eax
1511 pop edi // Restore register edi
1512 mov esp,ebp // Deallocate temporary space
1513 pop ebp
1514 ret
1515
1516 _sin:
1517 push ebp // Save register bp
1518 mov ebp,esp // Point to the stack frame
1519 fld qword ptr [ebp+8] // Load real from stack
1520 fsin // Take the sine
1521 pop ebp // Restore register bp
1522 ret
1523
1524 _sqrt:
1525 push ebp
1526 mov ebp,esp
1527 fld qword ptr [ebp+8] // Load real from stack
1528 fsqrt // Take the square root
1529 pop ebp
1530 ret
1531
1532 _tan:
1533 push ebp
1534 mov ebp,esp
1535 sub esp,4 // Allocate temporary space
1536 fld qword ptr [ebp+8] // Load real from stack
1537 fptan // Take the tangent
1538 fstp dword ptr [ebp-4] // Throw away the constant 1
1539 mov esp,ebp // Deallocate temporary space
1540 pop ebp
1541 ret