J'ai quelques questions sur Diviser des erreurs de dépassement sur l'architecture X86 ou X86_64. Dernièrement, j'ai lu sur les débordements entier. Habituellement, lorsqu'une opération arithmétique entraîne un débordement entier, le bit de transport ou le débit de débordement dans le registre des drapeaux est défini. Mais apparemment, selon Cet article , déborder des opérations de division Don ' t Définissez le débit de débordement, mais plutôt déclencher une exception matérielle, semblable à la division de zéro.
Maintenant, les débordements entier résultant de la division sont beaucoup plus rares que de dire la multiplication. Il n'y a que quelques façons de déclencher un débordement de la division. Une solution serait de faire quelque chose comme: p> Dans ce cas, en raison de la représentation du complément des deux entiers signés, vous ne pouvez pas représenter positif 32768 dans un 16 Bit Integer, de sorte que l'opération de division déborde, entraînant la valeur erronée de -32768. P> Quelques questions: p> 1) contrairement à ce que cet article dit, ce qui précède n'a pas causé une exception matérielle. J'utilise une machine X86_64 exécutant Linux et lorsque je divisez par zéro, le programme se termine par une exception de point flottante code>. Mais lorsque je provoque un débordement de la division, le programme continue comme d'habitude, ignorant silencieusement le quotient erroné. Alors, pourquoi cela ne provoque-t-il pas une exception matérielle? P> 2) Pourquoi les erreurs de division sont-elles traitées si sévèrement par le matériel, par opposition à d'autres débordements arithmétiques? Pourquoi une dépassement de multiplication (qui est beaucoup em> plus susceptible de se produire accidentellement) soit silencieusement ignorée par le matériel, mais un débordement de la division est censé déclencher une interruption fatale? P> == ========= edit fort> ============== P> D'accord, merci à tout le monde pour les réponses. J'ai eu des réponses en disant essentiellement que la division entière de 16 bits ci-dessus ne devrait pas causer de faute matérielle car le quotient est toujours inférieur à la taille du registre. Je ne comprends pas ça. Dans ce cas, le registre stockant le quotient est de 16 bits - qui est trop petit em> pour stocker signé positif 32768. Alors pourquoi une exception matérielle n'est-elle pas soulevée? P> Ok, Faisons-le directement dans l'assemblage en ligne GCC et voyons ce qui se passe: p> ceci simplifie simplement une valeur erronée: -32768 code>. Toujours pas d'exception matérielle, même si le registre stocke le quotient (AX) est trop petit pour s'adapter au quotient. Donc, je ne comprends pas pourquoi aucune faute matérielle n'est élevée ici. p> p>
7 Réponses :
Lorsque vous obtenez un débordement entier avec le complément d'entier 2 Ajouter / Soustrayer / Multipliez, vous avez toujours un résultat valide - il manque simplement quelques bits d'ordre élevé. Ce comportement est souvent utile, il ne serait donc pas approprié de générer une exception pour cela. P>
Avec la division entière, cependant, le résultat d'une fracture par zéro est inutile (car, contrairement à un point flottant, les entiers complémentaires de 2 n'ont aucune représentation INF). P>
Contrairement à ce que cet article dit, ce qui précède n'a pas provoqué une exception matérielle p> blockQuote>
L'article n'a pas dit cela. Est dit p>
... Ils génèrent une erreur de division si l'opérande source (diviseur) est zéro ou si le quotient est trop grand pour le registre désigné fort> p> blockQuote>
La taille du registre est définitivement supérieure à 16 bits (32 || 64) p>
Mais dans ce cas, le registre stocker le quotient n'est que de 16 bits, alors pourquoi une exception matérielle n'est-elle pas soulevée? Voir ma question modifiée pour plus de précision.
@ Channel72, le type de stockage du quotient n'est que de 16 bits. Le registre lui-même est de 32 bits.
@MSN: En X86, la taille du registre est variable. AX CODE> est un registre 16 bits même sur des machines de 64 bits, et c'est le seul moyen d'expliquer comment le résultat est tronqué ici.
@Msn, je suis confus. Le registre AX stocke le quotient et le registre AX est 16 bits
@Potatoswatter, Ah, eh bien, l'assemblée dans la poste éditée est fausse (voir le commentaire de Andreyt) mais je doute sincèrement que GCC utiliserait des opérations de 16 bits pour faire une fracture INT16_T. Et la norme ne dicte pas la manière dont l'opération de division est réellement mise en œuvre, seuls ses résultats. Quoi qu'il en soit, vous pouvez toujours obtenir le débordement entier pour la division, mais vous ne devriez pas essayer avec des types plus petits que int code> (puisque vous ne pouvez le faire qu'avec int_min / -1 de toute façon).
J'ai essayé le code C et génère en fait idiodi eax, ecx code> dans Visual Studio ...
Dans les opérations arithmétiques du langage C ne sont jamais effectuées dans les types plus petits que dans votre code d'assemblage que vous utilisez une division 16 bits, car vous avez spécifié et ce que vous avez fait avec Si vous souhaitez représenter Par exemple, dans mon expérience (pas GCC) Ce code P> int code>. Chaque fois que vous essayez d'arithmétiques sur des opérandes plus petits, ils sont d'abord soumis à des promotions intégrées qui les convertissent en
int code>. Si sur votre plate-forme
int code> est, disons, 32 bits larges, alors il n'y a aucun moyen de forcer un programme C pour effectuer une division 16 bits. Le compilateur générera à la place de la division 32 bits. C'est probablement pourquoi votre expérience C ne produit pas le débordement attendu sur la division. Si votre plate-forme a en effet 32 bits
int code>, votre meilleur pari serait d'essayer la même chose avec des opérandes 32 bits (c.-à-d. Diviser
int_min code> par
- 1 code>). Je suis presque sûr que vous pourrez éventuellement reproduire l'exception de trop-plein, même en code C.
bx code> comme opérande pour
idiovis code>. La division 16 bits sur X86 divise le dividende 32 bits stocké dans
dx: hache code> paire par le
idiovis code> opérande. C'est ce que vous faites dans votre code. La paire
DX: AX CODE> est interprétée comme un enregistrement composite 32 bits, ce qui signifie que le bit de panneau de cette paire est maintenant en réalité le bit de commande le plus élevé de
dx code>. Le bit de commande le plus élevé de
hache code> n'est plus un piqué de signe. P>
dx code>? Vous l'avez simplement effacé. Vous le définissez à 0. mais avec
dx code> défini sur 0, votre dividende est interprété comme positif em>! Du point de vue de la machine, une telle paire
dx: hache code> représente une valeur em> em>
+32768 code>. C'est à dire. Dans votre expérience de montage en langage, vous divisez
+32768 code> par
-1 code>. Et le résultat est
-32768 code>, comme cela devrait être. Rien d'inhabituel ici. P>
-32768 code> dans la paire
DX: AX CODE>, vous devez la signer, c'est-à-dire que vous avez Pour remplir
dx code> avec un motif de bits tout-un, au lieu de zéros. Au lieu de faire
XOR DX, DX CODE> Vous devez avoir initialisé
AX code> avec votre
-32768 code>, puis effectué
CWD code>. Cela aurait Signé-étendu
Ax code> dans
dx code>. P>
__asm {
mov AX, -32768
cwd
mov BX, -1
idiv BX
}
D'accord, je vois. Merci. Cela a déclenché la défaillance du matériel attendu.
Belle prise sur l'exemple de langue de montage!
La raison Votre exemple n'a pas généré une exception matérielle est due aux règles de promotion entier de C. Les opérandes plus petites que Quoi que Différents types de débordements sont traités différemment, considérons qu'au niveau de la machine X86, il n'y a vraiment aucune telle chose qu'un débordement de multiplication. Lorsque vous multipliez la hache par un autre registre, le résultat va dans la paire DX: AX, donc il y a toujours de la place pour le résultat, et donc aucune occasion de signaler une exception de trop-plein. Toutefois, en C et dans d'autres langues, le produit de deux int code> sont automatiquement favorisées à
intens code> avant que l'opération soit effectuée. p> li>
Ints code> est censé correspondre à un
int code>, donc il y a une telle chose que le débordement du niveau C. Le X86 est parfois défini sur (drapeau de débordement) sur
mul code> s, mais cela signifie simplement que la partie haute du résultat n'est pas nulle. P> li>
ol>
Les instructions multiples multiples 80386 utilisent un registre de destination unique qui a la même taille que la source. Ils fixent des drapeaux en cas de débordement, quel code peut ignorer ou non ignorer.
sur une implémentation avec 32 bits Si vous souhaitez essayer de causer une exception (qui peut encore ou non On se produit effectivement, c'est à la mise en œuvre), essayez: p> Vous devrez peut-être faire quelques astuces pour empêcher le compilateur de l'optimiser au moment de la compilation. P > p> int code>, votre exemple n'entraîne pas de débordement de division fort>. Il en résulte un
int code> parfaitement représentable, 32768, qui est ensuite converti en
int16_t code> de manière définie par la mise en œuvre lorsque vous effectuez la mission. Ceci est dû aux promotions par défaut spécifiées par le langage C et, par conséquent, une implémentation qui soulevait une exception ici serait non conforme.
Je vais conjecturer cela sur certains anciens ordinateurs, essayant de diviser par zéro entraînerait des problèmes graves (par exemple, placer le matériel dans un cycle sans fin d'essayer de soustraire suffisamment que le reste serait inférieur au dividende jusqu'à ce qu'un opérateur soit arrivé. Pour réparer les choses), et cela a commencé une tradition de diviser les débordements considérés comme des défauts plus graves que des débordements entier. P>
À partir d'un point de vue de la programmation, il n'y a aucune raison qu'un débordement de division inattendu devrait être plus ou moins grave qu'un débordement inattendu intégré (signé ou non signé). Compte tenu du coût de la division, le coût marginal de la vérification d'un drapeau de débordement serait assez léger. La tradition est la seule raison pour laquelle je puisse voir pour avoir un piège au matériel. P>
Vous parlez de comportement spécifique à un quincaillerie, mais vous le testez avec Code C. Cela n'a pas de sens. Pourquoi essayez-vous d'appliquer une spécification d'instructions de rassemblement à l'opérateur de division de langage C? Quelque chose vous fait penser que votre division C génère réellement l'instruction de division dont vous avez citée la spécification? Avez-vous vérifié que c'est le cas?
@Andreyt, d'accord bon point - j'ai mis à jour la question à essayer cela directement dans la langue d'assemblage
Vous avez représenté
-32768 code> dans le
dx: hache code> paire de manière incorrecte. En fait, vous divisez
+32768 code> par
-1 code>, c'est pourquoi obtenir
-32768 code>. Voir ma réponse.
Sur une implémentation avec
int code> 32 bits, votre exemple n'entraîne pas un débordement de division b>. Il en résulte un
int code> parfaitement représentable, 32768, qui est ensuite converti en
int16_t code> de manière définie par la mise en œuvre lorsque vous effectuez la mission. (Astuce: promotions par défaut de recherche)