Tp 9 : Le coprocesseur mathématique



L'objectif

Il est de vous montrer que le codage en assembleur i386, d'une instruction arithmétique telle que la multiplication, est différent selon que l'on a affaire à des nombres entiers ou à des nombres flottants.

Le temps imparti

1h30

Le sujet

Les calculs sur les nombres entiers sont effectués par l'Unité Arithmétique et Logique du microprocesseur; ceux sur les nombres flottants par le coprocesseur arithmétique aussi appelé Unité de Calculs en Virgule Flottante. Par la suite nous verrons comment sont codées en langage d'assemblage certaines fonctions trigonométriques que vous pouvez utiliser dans vos programmes en langage C.

A faire

Saisiret compiler le programme C suivant, qui ne fait que multiplier successivement deux entiers puis deux flottants.

  1. #include <stdio.h>
  2. int main2()
  3. {
  4. int a=2, b;
  5. double c=8.0, d;
  6. b = a*a;
  7. printf ("le carré de %d est : %d",a,b);
  8. c = d*d
  9. printf ("le carré de %f est : %f",c,d);
  10. return 0;
  11. }
  12. int main()
  13. {
  14. return main2();
  15. }

Le code assembleur généré ressemble alors à :

  1. .LC1:
  2. .string "Le carr\351 de %d est %d.\n"
  3. .LC2:
  4. .string "Le carr\351 de %f est %f.\n"
  5. .align 8
  6. .LC0:
  7. .long 0
  8. .long 1075838976
  9. .text
  10. .globl main
  11. main:
  12. pushl %ebp
  13. movl %esp, %ebp
  14. subl $56, %esp
  15. andl $-16, %esp
  16. movl $0, %eax
  17. subl %eax, %esp
  18. movl $2, -4(%ebp)
  19. fldl .LC0
  20. fstpl -16(%ebp)
  21. movl -4(%ebp), %eax
  22. imull -4(%ebp), %eax
  23. movl %eax, -8(%ebp)
  24. movl -8(%ebp), %eax
  25. movl %eax, 8(%esp)
  26. movl -4(%ebp), %eax
  27. movl %eax, 4(%esp)
  28. movl $.LC1, (%esp)
  29. call printf
  30. fldl -16(%ebp)
  31. fmull -16(%ebp)
  32. fstpl -24(%ebp)
  33. fldl -24(%ebp)
  34. fstpl 12(%esp)
  35. fldl -16(%ebp)
  36. fstpl 4(%esp)
  37. movl $.LC2, (%esp)
  38. call printf
  39. movl $0, %eax
  40. leave
  41. ret

Segmenter ce programme, et identifier les deux multiplications. Quelles instructions x86 sont utilisées ?

Le calcul de la fonction sinus se fait via l'appel d'une fonction C. En désassemblant la librairie mathématique, voici ce que l'on obtient :

080482b0 <__cos>:
 80482b0:	dd 44 24 04          				fldl   0x4(%esp)
 80482b4:	d9 ff                				fcos
 80482b6:	df e0                				fnstsw %ax
 80482b8:	a9 00 04 00 00       				test   $0x400,%eax
 80482bd:	75 01                				jne    80482c0 <__cos+0x10>
 80482bf:	c3                   				ret
 80482c0:	d9 eb                				fldpi
 80482c2:	d8 c0                				fadd   %st(0),%st
 80482c4:	d9 c9                				fxch   %st(1)
 80482c6:	d9 f5                				fprem1
 80482c8:	df e0                				fnstsw %ax
 80482ca:	a9 00 04 00 00       				test   $0x400,%eax
 80482cf:	75 f5                				jne    80482c6 <__cos+0x16>
 80482d1:	dd d9                				fstp   %st(1)
 80482d3:	d9 ff                				fcos
 80482d5:	c3                   				ret
 80482d6:	90                   				nop
 80482d7:	90                   				nop
 80482d8:	90                   				nop
 80482d9:	90                   				nop
 80482da:	90                   				nop
 80482db:	90                   				nop
 80482dc:	90                   				nop
 80482dd:	90                   				nop
 80482de:	90                   				nop
 80482df:	90                   				nop

080482e0 <__sin>:
 80482e0:	dd 44 24 04          				fldl   0x4(%esp)
 80482e4:	d9 fe                				fsin
 80482e6:	df e0                				fnstsw %ax
 80482e8:	a9 00 04 00 00       				test   $0x400,%eax
 80482ed:	75 01                				jne    80482f0 <__sin+0x10>
 80482ef:	c3                   				ret
 80482f0:	d9 eb                				fldpi
 80482f2:	d8 c0                				fadd   %st(0),%st
 80482f4:	d9 c9                				fxch   %st(1)
 80482f6:	d9 f5                				fprem1
 80482f8:	df e0                				fnstsw %ax
 80482fa:	a9 00 04 00 00       				test   $0x400,%eax
 80482ff:	75 f5                				jne    80482f6 <__sin+0x16>
 8048301:	dd d9                				fstp   %st(1)
 8048303:	d9 fe                				fsin
 8048305:	c3                   				ret
 8048306:	90                   				nop
 8048307:	90                   				nop
 8048308:	90                   				nop
 8048309:	90                   				nop
 804830a:	90                   				nop
 804830b:	90                   				nop
 804830c:	90                   				nop
 804830d:	90                   				nop
 804830e:	90                   				nop
 804830f:	90                   				nop

08048310 <__tan>:
 8048310:	dd 44 24 04          				fldl   0x4(%esp)
 8048314:	d9 f2                				fptan
 8048316:	df e0                				fnstsw %ax
 8048318:	a9 00 04 00 00       				test   $0x400,%eax
 804831d:	75 03                				jne    8048322 <__tan+0x12>
 804831f:	dd d8                				fstp   %st(0)
 8048321:	c3                   				ret
 8048322:	d9 eb                				fldpi
 8048324:	d8 c0                				fadd   %st(0),%st
 8048326:	d9 c9                				fxch   %st(1)
 8048328:	d9 f5                				fprem1
 804832a:	9b df e0             				fstsw  %ax
 804832d:	a9 00 04 00 00       				test   $0x400,%eax
 8048332:	75 f4                				jne    8048328 <__tan+0x18>
 8048334:	dd d9                				fstp   %st(1)
 8048336:	d9 f2                				fptan
 8048338:	dd d8                				fstp   %st(0)
 804833a:	c3                   				ret
 804833b:	90                   				nop
 804833c:	90                   				nop
 804833d:	90                   				nop
 804833e:	90                   				nop
 804833f:	90                   				nop
  

Rappels : l'instruction fnstsw %ax transfère le registre d'état dans le registre AX. L'instruction fprem1 calcule le reste de la division entière.
Expliquez le fonctionnement de ces fonctions, sachant que l'instruction test $0x400 teste la valeur du bit 10, et que ce bit correspond à Argument hors bornes (voir manuel Intel vol.1, pages 8-6 et 8-8).


Pour ceux qui veulent aller plus loin...

Je vous propose d'écrire en assembleur (utilisant la FPU) un petit programme résolvant une équation du second degré. Bien entendu, la saisie et l'affichage des données peut être fait en langage C...


Retour à la liste des TP