Question

J'essaie de comprendre un assemblage.

L'assemblage comme suit m'intéresse la ligne testl :

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 de testl entre % eax et % eax ? Je pense que les détails de ce que ce code n’a pas d’importance, j’essaie simplement de comprendre le test avec lui-même - la valeur ne serait-elle pas toujours vraie?

Était-ce utile?

La solution

Il teste si eax est égal à 0, ou supérieur ou inférieur. Dans ce cas, le saut est pris si eax est 0.

Autres conseils

La signification de test est de combiner ET les arguments ensemble et de vérifier 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 , raison pour laquelle les compilateurs le font généralement de cette façon.

L'instruction de test effectue une opération logique AND entre les opérandes mais ne réécrit pas le résultat dans un registre. Seuls les drapeaux sont mis à jour.

Dans votre exemple, test eax, eax définira l'indicateur zéro si eax est égal à zéro, l'indicateur de signe si le bit le plus élevé est défini, ainsi que d'autres indicateurs.

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 ceci:

cmp eax, 0
je  somewhere

Cela a la même fonctionnalité mais nécessite quelques octets plus d'espace de code. C'est la raison pour laquelle le compilateur a émis un test au lieu d'une comparaison.

test est comme et , sauf qu'il écrit uniquement FLAGS, en laissant ses deux entrées non modifiées. Avec deux entrées différentes , il est utile de vérifier si certains bits sont tous nuls 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 ses deux bits les plus bas mis à zéro).

test eax, eax définit tout les drapeaux exactement de la même manière que cmp eax, 0 aurait :

  • CF et OF effacés (AND / TEST fait toujours cela; et soustraire zéro ne produit jamais de report)
  • ZF, SF et PF en fonction de la valeur dans EAX. ( a = a & a; a = a-0 )

(Sauf pour l'AF obsolète (indicateur de port auxiliaire utilisé par les instructions ASCII / BCD). TEST le laisse non défini , mais CMP le définit "en fonction du résultat" . Puisque la soustraction de zéro ne peut pas produire de retenue du 4ème au 5ème bit, CMP doit toujours effacer l’AF).

TEST est plus petit (pas d’immédiat) et parfois plus rapide (possibilité de fusionner des macros en un uop de comparaison et de branchement sur plus de processeurs dans plus de cas que CMP). Cela permet à de tester l'idiome préféré pour tester un registre à zéro ou non .

La seule raison courante pour utiliser CMP avec un 0 immédiat, c’est lorsque vous souhaitez comparer un opérande mémoire (par exemple, cmpb $ 0, (% esi) pour rechercher un octet final de fin la fin d'une chaîne de style C de longueur implicite).

AVX512F ajoute les kortestw k1, k2 . a> et AVX512DQ / BW (Skylake mais pas KNL), ajoutez ktestb / w / d / q k1, k2 , qui fonctionnent sur les registres de masque AVX512 (k0..k7) mais définissent tout de même les DRAPEAUX normaux, comme le fait test , de la même manière que entier OU ou ET instructions faire.

kortestw k1, k1 est la méthode idiomatique de branchement / cmovcc / setcc basée sur un résultat de comparaison AVX512, remplaçant SSE / AVX2 (v) pmovmskb / ps / pd + test ou cmp .

L'utilisation de jz ou je peut être source de confusion.

jz et je sont littéralement les 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 les sorties asm des compilateurs) n’en utiliseront jamais qu’un seul, la distinction sémantique est alors perdue.

cmp et sous définissent ZF lorsque leurs deux entrées sont égales (c'est-à-dire que le résultat de la soustraction est 0). je (saut si égal) est le synonyme sémantiquement pertinent.

test% eax,% eax / et% eax,% eax définit à nouveau ZF lorsque le résultat est égal à zéro, mais il n'y a pas d '"égalité". tester. ZF après test ne vous dit pas si les deux opérandes étaient égaux. Donc jz (saut si zéro) est le synonyme sémantiquement pertinent.

Cet extrait de code provient d'un sous-programme auquel un pointeur a été attribué, probablement une structure ou un objet. La 2ème ligne supprime ce pointeur en récupérant une valeur de cette chose - éventuellement un pointeur ou peut-être simplement un int, stocké comme son 2ème membre (offset +4). Les 3ème et 4ème lignes testent cette valeur à zéro (NULL s'il s'agit d'un pointeur) et ignorent les quelques opérations suivantes (non affichées) si elle est égale à 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'homme?) qui l'a écrit aurait pu penser qu'un test serait plus rapide - en prenant en compte tous les éléments modernes de la CPU, comme pipelining et register renommer. C'est dans le même sac à mal que l'idée de nettoyer un registre avec XOR EAX, EAX (que j'ai vu sur la plaque d'immatriculation de quelqu'un dans le Colorado!) Plutôt que sur le MOV EAX, # 0 (j'utilise une notation plus ancienne, mais peut-être plus lente) ).

Dans asm, comme Perl, TMTOWTDI.

Si eax est égal à zéro, il effectuera le saut conditionnel, sinon il poursuivra son exécution à 319e9

Dans certains programmes, ils peuvent être utilisés pour vérifier un débordement de mémoire tampon. Tout en haut de l'espace alloué, un 0 est placé. Une fois les données saisies dans la pile, il recherche le 0 au tout début de l’espace alloué pour s’assurer que cet espace n’est pas saturé.

Il a été utilisé dans l'exercice d'empilage d'exploits-exercices pour vérifier s'il débordait et s'il n'y en avait pas et s'il y avait un zéro, l'affichage s'affichera "Réessayer"

0x080483f4 <main+0>:    push   ebp
0x080483f5 <main+1>:    mov    ebp,esp
0x080483f7 <main+3>:    and    esp,0xfffffff0
0x080483fa <main+6>:    sub    esp,0x60                     
0x080483fd <main+9>:    mov    DWORD PTR [esp+0x5c],0x0 ;puts a zero on stack
0x08048405 <main+17>:   lea    eax,[esp+0x1c]
0x08048409 <main+21>:   mov    DWORD PTR [esp],eax
0x0804840c <main+24>:   call   0x804830c <gets@plt>
0x08048411 <main+29>:   mov    eax,DWORD PTR [esp+0x5c] 
0x08048415 <main+33>:   test   eax,eax                  ; checks if its zero
0x08048417 <main+35>:   je     0x8048427 <main+51>
0x08048419 <main+37>:   mov    DWORD PTR [esp],0x8048500 
0x08048420 <main+44>:   call   0x804832c <puts@plt>
0x08048425 <main+49>:   jmp    0x8048433 <main+63>
0x08048427 <main+51>:   mov    DWORD PTR [esp],0x8048529
0x0804842e <main+58>:   call   0x804832c <puts@plt>
0x08048433 <main+63>:   leave
0x08048434 <main+64>:   ret

nous avons pu voir le jg jle Si testl% edx,% edx. jle .L3 nous pourrions facilement trouver jle comme (SF ^ OF) | ZF , si% edx est égal à zéro, ZF = 1, mais si% edx n'est pas zéro et vaut -1, après le testl, le OF = 0 et le SF = 1, donc l'indicateur = true, qui implémente le saut désolé, mon anglais est médiocre

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top