x86 assemblage: instruction INC et DEC et drapeau de débordement
dans x86 assembly, le drapeau overflow est activé lorsqu'une opération add
ou sub
est exécutée sur un dépassement d'entier signé, et le drapeau carry est activé lorsqu'une opération est exécutée sur un dépassement d'entier non signé.
toutefois, en ce qui concerne les instructions inc
et dec
, la situation semble quelque peu différente. Selon ce site web , l'instruction inc
n'affecte pas du tout le port du drapeau.
mais je ne peux trouver aucune information sur la façon dont inc
et dec
affectent le drapeau de débordement, si à tous.
Faire inc
ou dec
définir l'indicateur de débordement lors d'un dépassement d'entier se produit? Et est ce comportement identique pour les entiers signés et non signés?
============================= MODIFIER =============================
Ok, donc essentiellement, le consensus ici est que L'INC et le DEC devraient se comporter de la même façon que L'ADD et le SUB, en termes de mise en place des drapeaux, à l'exception du carry flag. C'est aussi ce qui est écrit dans le manuel Intel.
le problème est que je ne peux pas réellement reproduire ce comportement dans la pratique, quand il s'agit d'entiers non signés.
envisager le code d'assemblage suivant (en utilisant L'assemblage en ligne GCC pour faciliter l'impression des résultats.)
int8_t ovf = 0;
__asm__
(
"movb $-128, %%bh;"
"decb %%bh;"
"seto %b0;"
: "=g"(ovf)
:
: "%bh"
);
printf("Overflow flag: %dn", ovf);
ici nous décrémentons une valeur signée de 8 bits de -128. Depuis -128 est la plus petite valeur possible, un débordement est inévitable. Comme prévu, cela imprime: Overflow flag: 1
mais quand nous faisons la même chose avec une valeur non signée , le comportement n'est pas comme je m'y attendais:
int8_t ovf = 0;
__asm__
(
"movb 5, %%bh;"
"incb %%bh;"
"seto %b0;"
: "=g"(ovf)
:
: "%bh"
);
printf("Overflow flag: %dn", ovf);
ici je incrémente une valeur non signée de 8 bits de 255. Depuis 255 est la plus grande valeur possible, un débordement est inévitable. Cependant, ce imprime: Overflow flag: 0
.
Hein? Pourquoi n'a-t-il pas placé le drapeau de débordement dans ce cas?
7 réponses
l'indicateur de débordement est placé lorsqu'une opération entraînerait un changement de signal. Votre code est très proche. J'ai pu mettre le drapeau de L'OF avec le code suivant (VC++):
char ovf = 0;
_asm {
mov bh, 127
inc bh
seto ovf
}
cout << "ovf: " << int(ovf) << endl;
lorsque BH est incrémenté, le MSB passe de 0 à 1, provoquant le réglage de la valeur de OF.
ce paramètre définit également le de:
char ovf = 0;
_asm {
mov bh, 128
dec bh
seto ovf
}
cout << "ovf: " << int(ovf) << endl;
n'oubliez pas que le processeur ne fait pas de distinction entre les numéros signés et les numéros non signés. Quand vous utilisez 2 complément arithmétique, vous pouvez avoir un ensemble d'instructions qui traitent les deux. Si vous voulez tester non signés, de dépassement, vous devez utiliser le porte drapeau. Puisque INC/DEC n'affecte pas le drapeau carry, vous devez utiliser ADD / SUB pour ce cas.
Intel® 64 et IA-32 Architectures Développeur de Logiciels, les Manuels de
Regardez le manuel approprié Jeu d'Instructions de Référence, A-M . Chaque instruction est documentée avec précision.
Voici la section INC sur les drapeaux concernés:
le drapeau des FC n'est pas affecté. Les drapeaux OF, SZ, ZF, AZ et PF sont positionnés en fonction du résultat.
essayez de changer votre test pour passer dans le nombre plutôt que le code dur, puis avoir une boucle qui essaie tous les 256 numéros pour trouver celui si un qui affecte le drapeau. Ou ont l'asm effectuer la boucle et de sortie quand il frappe le drapeau et ou quand il s'enroule autour du nombre, il a commencé avec (commencer avec quelque chose d'autre que 0x00, 0x7f, 0x80, ou 0xFF).
EDIT
.globl inc inc: mov , %eax top: inc %al jo done jmp top done: ret .globl dec dec: mov , %eax topx: dec %al jo donex jmp topx donex: ret
Inc déborde quand il passe de 0x7F à 0x80. dec débordements quand il va de 0x80 à 0x7F, je soupçonne que le problème est dans la façon dont vous utilisez assembleur en ligne.
comme beaucoup d'autres réponses l'ont souligné, INC
et DEC
n'affectent pas le CF
, tandis que ADD
et SUB
le font.
ce qui n'a pas encore été dit, cependant, c'est que cela pourrait faire une différence de performance. Non pas que vous seriez généralement ennuyé par cela à moins que vous essayez d'optimiser l'enfer hors d'une routine, mais essentiellement ne pas définir le CF
signifie que INC
/ DEC
n'écrivez qu'à une partie de les drapeaux de registre qui peut causer une de drapeaux partiels registre de décrochage , voir Intel ® 64 et IA-32 Optimisation des Architectures Manuel ou Agner Brouillard d'optimisation de manuels .
sauf pour le carry flag inc met les drapeaux de la même manière que add operand 1 le ferait.
le fait que inc n'affecte pas le carry flag est très important.
http://oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter_6/CH06-2.html#HEADING2-117
ce que le processeur fait est de mettre les drapeaux appropriés pour les résultats de ces instructions (add, adc, dec, inc, sbb, sub) pour les cas signés et non signés est deux résultats de drapeau différents pour chaque op. L'autre solution serait d'avoir deux séries d'instructions, l'une pour les drapeaux liés à la signature et l'autre pour les drapeaux non liés à la signature. Si le compilateur émetteur utilise des variables non signées dans l'opération, il testera carry et zero (jc, jnc, jb, jbe etc), s'il est signé il teste overflow, signe et zéro (jo, jno, jg, jng, jl, jle etc).
le CPU/ALU est seulement capable de traiter des nombres binaires non signés, et puis il utilise, CF, AF, SF, ZF, etc., pour vous permettre de décider s'il faut l'utiliser comme un numéro signé (de), un numéro non signé (CF) ou un numéro BCD (AF).
à propos de votre problème, n'oubliez pas de considérer les nombres binaires eux-mêmes, comme non signé.
aussi, le débordement et le de exigent 3 numéros: Le nombre d'entrée, un deuxième numéro à utiliser dans le calcul, et le nombre de résultat.
Débordement est activée uniquement si les premier et deuxième nombres ont la même valeur pour le bit de signe (le bit le plus significatif) et le résultat est un signe différent. comme dans, l'ajout de 2 nombres négatifs a donné un nombre positif, ou l'ajout de 2 nombres positifs a donné un nombre négatif:
if( (Sign_Num1==Sign_Num2) && (Sign_Result!=Sign_Num1) ) OF=1;
else OF=0;
pour votre premier problème, vous utilisez -128
comme premier numéro. Le second numéro est implicitement -1
, utilisé par L'instruction DEC. Donc, nous avons vraiment les nombres binaires 0x80
et 0xFF
. Les deux ont le bit de signe réglé à 1. Le résultat est 0x7F
, qui est un nombre avec le bit de signe à 0. Nous avons obtenu 2 nombres initiaux avec le même signe, et un résultat avec un signe différent, donc nous indiquons un débordement. -128-1
résultat 127
, et donc l'indicateur de débordement est réglé pour indiquer un résultat signé erroné.
Pour ton deuxième problème, vous êtes à l'aide de 255
comme le premier numéro. Le deuxième numéro est implicitement 1
, utilisé par L'instruction INC. Donc, nous avons vraiment les nombres binaires 0xFF
et 0x01
. Les deux ont un signe différent, donc il n'est pas possible d'obtenir un débordement (il n'est possible de déborder qu'en ajoutant essentiellement deux numéros du même signe, mais il n'est jamais possible de déborder avec deux numéros d'un signe différent parce qu'ils ne conduiront jamais à aller au-delà de la valeur signée possible). le résultat est 0x00
, et il ne met pas le drapeau overflow parce que 255+1
, ou plus exactement, -1+1
donne 0, ce qui est évidemment correct pour l'arithmétique signée.
N'oubliez pas que pour que le drapeau overflow soit positionné, les 2 nombres ajoutés/soustraits doivent avoir le bit de signe avec la même valeur, et ensuite le résultat doit avoir un bit de signe avec une valeur différente d'eux.