J'essaie de comprendre un assemblage.
Le montage comme suit, je suis intéressé par la testl
ligne:
000319df 8b4508 movl 0x08(%ebp), %eax
000319e2 8b4004 movl 0x04(%eax), %eax
000319e5 85c0 testl %eax, %eax
000319e7 7407 je 0x000319f0
J'essaie de comprendre ce point testl
entre %eax
et %eax
? Je pense que les spécificités de ce code ne sont pas importantes, j'essaie simplement de comprendre le test avec lui-même - la valeur ne serait-elle pas toujours vraie?
assembly
x86
instructions
maxpenguin
la source
la source
test
etcmp
. Oui, je comprends que c'est votre opinion sur la base de vos commentaires à Cody. Cependant, le mettre dans mon message est une autre affaire; ce n'est pas une affirmation que je suis prêt à maintenir, simplement parce que je ne sais pas si c'est identique dans tous les cas.je
,jz
,cmp
ettest
, et non JE, JZ, CMP ou TEST. Je suis difficile comme ça.test a,a
etcmp $0,a
définir des indicateurs de manière identique; merci de souligner que c'est une affirmation non triviale. re: TEST vstest
.: récemment, j'ai commencé à utiliser des majuscules comme les manuels d'Intel. Mais quand je parle des mnémoniques AT&T et des mnémoniques Intel, j'utilise letestb
style pour AT&T. IDK si cela aide à la lisibilité.La signification de
test
est de ET les arguments ensemble, et vérifiez le résultat pour zéro. Donc, ce code teste si EAX est égal à zéro ou non.je
sautera si zéro.BTW, cela génère une instruction plus petite que
cmp eax, 0
ce qui est la raison pour laquelle les compilateurs le feront généralement de cette façon.la source
L'instruction de test effectue une opération ET logique entre les opérandes mais ne réécrit pas le résultat dans un registre. Seuls les drapeaux sont mis à jour.
Dans votre exemple, le test eax, eax définira l'indicateur zéro si eax vaut zéro, l'indicateur de signe si le bit le plus élevé est défini et quelques autres indicateurs également.
L'instruction Jump if Equal (je) saute si l'indicateur zéro est défini.
Vous pouvez traduire le code en un code plus lisible comme celui-ci:
Cela a la même fonctionnalité mais nécessite quelques octets de plus d'espace de code. C'est la raison pour laquelle le compilateur a émis un test au lieu d'une comparaison.
la source
test eax, eax
etcmp eax, 0
tous les deux définissent tous les indicateurs et les définissent sur des valeurs identiques. Les deux instructions définissent tous les indicateurs "en fonction du résultat". La soustraction0
ne peut jamais produire de report ou de débordement. Votre argument est correct pour tout immédiat autre que 0, mais pas pour 0.test
est commeand
, sauf qu'il n'écrit que des FLAGS, laissant ses deux entrées inchangées. Avec deux entrées différentes , il est utile pour tester si certains bits sont tous à zéro ou si au moins un est défini. (par exemple,test al, 3
définit ZF si EAX est un multiple de 4 (et a donc tous les deux ses deux bits inférieurs à zéro).test eax,eax
définit tous les drapeaux de la même manière que lecmp eax, 0
ferait :a = a&a = a-0
).(PF comme d'habitude n'est défini qu'en fonction des 8 bits bas )
Sauf pour l'AF obsolète (indicateur de report auxiliaire, utilisé par les instructions ASCII / BCD). TEST le laisse indéfini , mais CMP le définit "en fonction du résultat" . Étant donné que la soustraction de zéro ne peut pas produire de report du 4ème au 5ème bit, CMP doit toujours effacer AF.
TEST est plus petit (pas immédiat) et parfois plus rapide (peut macro-fusionner en un uop de comparaison et de branchement sur plus de processeurs dans plus de cas que CMP). Cela fait de
test
l'idiome préféré pour comparer un registre à zéro . C'est une optimisation de judascmp reg,0
que vous pouvez utiliser quelle que soit la signification sémantique.La seule raison courante d'utiliser CMP avec un 0 immédiat est lorsque vous souhaitez effectuer une comparaison avec un opérande mémoire. Par exemple,
cmpb $0, (%esi)
pour rechercher un octet de fin de zéro à la fin d'une chaîne de style C de longueur implicite.AVX512F ajoute
kortestw k1, k2
et AVX512DQ / BW (Skylake-X mais pas KNL) ajoutektestb/w/d/q k1, k2
, qui fonctionnent sur les registres de masque AVX512 (k0..k7) mais définissent toujours des FLAGs réguliers comme letest
font, de la même manière que les entiersOR
ou lesAND
instructions. (Un peu comme SSE4ptest
ou SSEucomiss
: les entrées dans le domaine SIMD et aboutissent à des FLAGS entiers.)kortestw k1,k1
est la manière idiomatique de créer un branchement / cmovcc / setcc basé sur un résultat de comparaison AVX512, en remplaçant SSE / AVX2(v)pmovmskb/ps/pd
+test
oucmp
.L'utilisation de
jz
vs.je
peut être déroutante.jz
etje
sont littéralement la même instruction , c'est-à-dire le même opcode dans le code machine. Ils font la même chose, mais ont une signification sémantique différente pour les humains . Les désassembleurs (et généralement la sortie asm des compilateurs) n'en utiliseront qu'un seul, donc la distinction sémantique est perdue.cmp
etsub
définissez ZF lorsque leurs deux entrées sont égales (c'est-à-dire que le résultat de la soustraction est 0).je
(jump if equal) est le synonyme sémantiquement pertinent.test %eax,%eax
/and %eax,%eax
définit à nouveau ZF lorsque le résultat est nul, mais il n'y a pas de test "d'égalité". ZF après le test ne vous dit pas si les deux opérandes étaient égaux. Doncjz
(sauter si zéro) est le synonyme sémantiquement pertinent.la source
test
bitand
, ce n'est peut-être pas évident pour les gens qui apprennent simplement l'assemblage (et qui sont paresseux / inconscients pour vérifier le guide de référence des instructions toutes les 60 secondes;) :)).kortest*
etktest*
pendant que j'y étais.Cet extrait de code provient d'une sous-routine qui a reçu un pointeur vers quelque chose, probablement une structure ou un objet. La 2ème ligne déréférence ce pointeur, récupérant une valeur de cette chose - peut-être lui-même un pointeur ou peut-être juste un int, stocké comme son 2ème membre (offset +4). Les 3e et 4e lignes testent cette valeur pour zéro (NULL s'il s'agit d'un pointeur) et sautent les quelques opérations suivantes (non illustrées) s'il est égal à zéro.
Le test pour zéro est parfois codé comme une comparaison avec une valeur zéro littérale immédiate, mais le compilateur (ou l'humain?) Qui a écrit cela aurait pu penser qu'une opération de test fonctionnerait plus rapidement - en tenant compte de tous les éléments du processeur modernes tels que le pipelining et le registre renommer. C'est à partir du même sac d'astuces qui contient l'idée d'effacer un registre avec XOR EAX, EAX (que j'ai vu sur la plaque d'immatriculation de quelqu'un dans le Colorado!) Plutôt que l'évident mais peut-être plus lent MOV EAX, # 0 (j'utilise une notation plus ancienne ).
Dans asm, comme perl, TMTOWTDI.
la source
Si eax vaut zéro, il effectuera le saut conditionnel, sinon il continuera l'exécution à 319e9
la source
Dans certains programmes, ils peuvent être utilisés pour vérifier un dépassement de mémoire tampon. Tout en haut de l'espace alloué, un 0 est placé. Après avoir entré des données dans la pile, il recherche le 0 au tout début de l'espace alloué pour s'assurer que l'espace alloué n'est pas débordé.
Il a été utilisé dans l'exercice stack0 des exploits-exercices pour vérifier s'il avait débordé et s'il n'y en avait pas et qu'il y avait un zéro, il afficherait "Try again"
la source
cmp DWORD PTR [esp+0x5c], 0
/jz 0x8048427 <main+51>
aurait été plus efficace qu'une charge MOV séparée et ensuite TEST. Ce n'est guère un cas d'utilisation courant pour rechercher un zéro.nous pourrions voir le jg,jle Si
testl %edx,%edx. jle .L3
nous pouvions trouver facilement jle est suit(SF^OF)|ZF
, si% edx est nul, ZF = 1, mais si% edx n'est pas nul et vaut -1, après le testl, l'OF = 0, et le SF = 1, donc le drapeau = true, qui implémente le saut. Désolé, mon anglais est médiocrela source