12
votes

Moyen le plus simple de supprimer quelque chose de la pile FPU

J'ai eu des problèmes récemment avec des débordements de pile FPU. J'ai réussi à le suivre dans une fonction de bibliothèque de buggy qui pousse une valeur détruite sur la pile FPU à chaque fois qu'elle s'appelle et ne le nettoie jamais.

Heureusement, cela est facilement reproductible et je sais exactement quelles conditions le causent. Je peux déposer un bloc d'Inline ASM dans la routine qui appelle cette routine pour faire sauter la valeur supérieure de la pile FPU ... sauf que je ne sais pas tout à fait quoi écrire. Mon asm-fu est juste à Middlin ', mais pas que fort.

Alors, quel est le moyen le plus simple de se débarrasser de la valeur supérieure de la pile FPU dans l'assemblage X86, en supposant que les ordures et je m'en fiche de la valeur?


1 commentaires

Pour l'enregistrement, X87 est obsolète. Le code moderne utilisera normalement les registres XMM, même pour Scalar FP Math, avec des instructions telles que ajoute (scalaire unique de précision) ou addsd (Double scalaire) . Regardez le code généré du compilateur pour toute fonction FP pour des exemples.


4 Réponses :


9
votes

Si vous savez combien vous devez ajuster la pile par, vous pouvez utiliser FINCSTP . Vous souhaitez également ffrae les registres que vous incrémentez-vous.

Cependant, la solution la plus simple est probablement d'utiliser l'une des opérations de transfert de données Popping, telles que FSTP . Normalement, vous stockeriez le résultat dans une zone de mémoire pour une utilisation ultérieure, quelque chose comme: xxx

mais, si vous savez que vous voulez juste jeter la valeur, vous pouvez utiliser ST (0) AS la destination, enregistrant l'exigence de la mémoire: xxx

voir ici pour un guide détaillé sur les instructions (en particulier Ce bit ).


2 commentaires

Notez que 'FSTP St (0)' nécessite une horloge. Ça ne va pas mieux que ça.


@ALBERTVANDERHORST: Les processeurs Superscalar peuvent facilement faire mieux que cela. FSTP / FST avec une destination d'enregistrement a un débit de 0,5C (I.e. 2 par horloge) sur HASWELL / SKYLAKE. agner.org/optimize . Enregistrer le renommage S'occupe de la dépendance via le pointeur haut de pile.



2
votes

Poussez-la de la pile avec une instruction (rapide) qui apparaît. 8087 Ensemble d'instructions

Si cela ne fonctionne pas, FUCOMPP apparaît deux fois.


0 commentaires

4
votes

Si ST0 est le seul registre X87 utilisé, vous pouvez le vider avec: xxx

mais c'est différent d'une pop normale s'il y a plusieurs piles s'il y a plusieurs piles Les registres utilisés, car ils ne réglèrent pas le pointeur haut de pile (champ supérieur du mot d'état X87).

voir Le chapitre Registers du tutoriel Swey FPU X87 .

ST1 serait toujours ST1 après libération ST0 au lieu de sauter, il n'est donc normalement pas ce que vous voulez et n'a pas d'avantage significatif sur FSTP ST0 . >


9 commentaires

Cela ne fonctionne pas. ST0 est étiqueté comme vide, mais cela n'affecte rien, à l'exception du mot tag FPU.


Je ne sais pas quoi d'autre que vous voudriez affectés, car c'est la définition de ce qui est dans le registre.


Bien sûr, vous voulez que le pointeur de pile ait également changé. J'ai vérifié expérimentalement (par petits mots de code, mon quatrième, CIForth) que votre solution ne fonctionne pas comme prévu. Voir la réponse donnée par les this qui est correct.


Pourquoi voudrais-je que le SP a changé? La pile est vide, peu importe où vous commencez à le remplir.


Oh je l'obtiens, dans ma réponse, il dit "Top" de la valeur, c'est une mauvaise formulation. Je voulais dire si la valeur supérieure est la seule valeur sur la pile. "Bas" serait correct.


Si vous pensez que la modification de la valeur supérieure à la valeur inférieure rend votre réponse correcte, vous devez éditer cela. Je l'ai fait pour vous, mais vous vous êtes senti obligé de signaler une carence dans votre réponse. Selon mon autre commentaire, on peut assurer que cela est sauvegardé mon expérimentation. Albert


J'étais un peu surpris que quelqu'un avec votre réputation donnerait une réponse incorrecte. Maintenant, je vois que c'est littéralement correct, désolé. S'il n'y a qu'un seul élément sur la pile et la pile est autrement vide, puis avec le réglage de ce mot d'étiquette, tous les mots d'étiquette indiquent vide et en effet pour cette pile circulaire, cela ne compte pas où le pointeur de la piste pointe. Je ne peux pas voir Wheeler indiquer qu'il n'y a qu'un seul élément sur la pile, cependant. Groetjes Albert


Oui, la formulation dans la réponse n'était pas claire sur ce que je voulais dire.


@ Jensbjörnhager: Votre mise à jour était techniquement correcte, mais toujours facile à interpréter mal pour les personnes qui ne savaient pas assez d'environ X87 pour même penser à la seule-maladie à 1-registre-utilisation étant pertinente / importante. Je réécrit fondamentalement la réponse autre que le bloc de code à quelque chose qui vaut la peine d'être upvote.



13
votes

Pour Delphi / Basm, à mon avis, le moyen le plus simple de sauter la pile FPU une fois:

asm
 fstp st(0)
end;


1 commentaires

C'est en fait la bonne réponse. La plupart des implémentations X87 sont optimisées pour ce boîtier et n'effectueront même pas le transfert, affichez simplement la valeur de la pile.