AMD64 — nopw instructions de montage?
Dans cette sortie du compilateur, j'essaie de comprendre comment le code machine de codage de la nopw
instruction fonctionne:
00000000004004d0 <main>:
4004d0: eb fe jmp 4004d0 <main>
4004d2: 66 66 66 66 66 2e 0f nopw %cs:0x0(%rax,%rax,1)
4004d9: 1f 84 00 00 00 00 00
Il y a une discussion sur la "nopw" à http://john.freml.in/amd64-nopl. Quelqu'un peut-il expliquer le sens de 4004d2-4004e0? En regardant l'opcode liste, il semble que 66 ..
codes sont multi-octets expansions. Je sens que je pourrais probablement obtenir une meilleure réponse à ce que je voudrais, à moins que j'ai essayé d'analyser l'opcode liste de quelques heures.
Que l'asm de sortie est la suivante (fou) de code en C, ce qui optimise les réduire à une simple boucle infinie:
long i = 0;
main() {
recurse();
}
recurse() {
i++;
recurse();
}
Lorsqu'il est compilé avec gcc -O2
, le compilateur reconnaît la récursivité infinie et il tourne dans une boucle infinie; il le fait si bien, en fait, qu'il fait des boucles dans le main()
sans appel de la recurse()
fonction.
note de l'éditeur: les fonctions de remplissage avec des Opr n'est pas spécifique à une boucle infini. Voici un ensemble de fonctions avec une gamme de longueurs d'Opr, sur le Godbolt compilateur explorer.
- Sommes-nous simplement en regardant aléatoire indésirable rembourrage ici?
- Peut-être! Je ne sais pas vraiment! C'est la beauté de tout cela! WHEEE. Vraiment, si, je reçois de la liés que le processeur SERAIT le chargement d'un bloc comme une instruction pour l'optimisation de la vitesse, mais grâce à la
jmp
, il ne le fait pas. Je viens d'obtenir le sens de l'il. Je sais ce que 0x90, mais je ne sais pas ce qu'il se passe avec66 .. ..
, ou pourquoi il est de 72 bits. - Ce n'est pas la raison ici, mais vous pouvez trouver Mon, quelle étrange Opr, vous avez! - Le Vieux Chose de Nouveau une lecture intéressante.
- nopl: stackoverflow.com/questions/12559475/...
Vous devez vous connecter pour publier un commentaire.
La
0x66
octets sont un "Opérande-Taille de Remplacer" le préfixe. Ayant plus d'un de ces équivaut à avoir un.La
0x2e
est un 'null préfixe" en mode 64 bits (c'est un CS: segment de remplacer sinon, c'est pourquoi il montre jusqu'à l'assemblée mnémonique).0x0f 0x1f
est un 2 octets opcode pour un NOP qui prend un ModRM octet0x84
est ModRM octet qui, dans ce cas, les codes pour un mode d'adressage qui utilise plus de 5 octets.Certains Processeurs sont lents à décoder les instructions avec beaucoup de préfixes (par exemple, plus de trois), donc une ModRM octet qui indique un SIB + disp32 est une bien meilleure façon d'utiliser un supplément de 5 octets de plus de cinq octets de préfixe.
Essentiellement, ces octets sont une longue instruction NOP qui ne sera jamais exécuté de toute façon. Il est là pour s'assurer que la fonction suivante est aligné sur une de 16 octets à la limite, parce que le compilateur émet un
.p2align 4
la directive, de sorte que l'assembleur collier avec un NOP. gcc par défaut pour les architectures x86 est-falign-fonctions=16
. Pour l'Opr, qui sera exécuté, le choix optimal de longue NOP dépend de la microarchitecture. Pour une microarchitecture qui étouffe sur de nombreux préfixes, comme Intel Silvermont ou AMD K8, deux Opr, avec 3 préfixes chacun pourrait avoir décodé rapidement.L'article du blog de la question liée à ( http://john.freml.in/amd64-nopl ) explique pourquoi le compilateur utilise un complexe unique NOP instruction au lieu d'un tas de octet 0x90 NOP instructions.
Vous pouvez trouver les détails sur le codage d'instruction dans d'AMD tech ref documents:
Principalement dans le "AMD64 Architecture Programmer's Manual Volume 3: l'Usage Général et les Instructions du Système". Je suis sûr que Intel références techniques pour l'architecture 64 bits auront les mêmes informations (et peut-être même plus compréhensible).
66
opérande de taille préfixe 5 fois de plus, c'est beaucoup plus grave qu'un mod/rm qui code pour un mode d'adressage qui utilise un SIB + disp32.L'assembleur (pas le compilateur) plaquettes de code jusqu'à la prochaine limite d'alignement avec la plus longue instruction NOP il peut trouver qui convient. C'est ce que vous voyez.
Je suppose que c'est juste la branche-delay.
Je pense que le nopw est indésirable - je n'est jamais lu dans votre programme, il n'y a donc pas besoin de l'incrémenter.
i
m'a donné un moyen pratique de vérifier la taille de la pile lorsqu'elle a échoué. Gdb, dans la mesure de mes faibles connaissances en va, n'a pas une "impression de la taille de la pile de la clé". Il est en outre intéressant de regarder le compilateur supprimer l'incrémentation d'une fois que le niveau d'optimisation est intensifié. Le programme est volontairement "insensé".nop
(nopw
ici) viennent de cette façon. La normenop
est 0x90 et venons de le répéter. Mettrei
là comme une nouvelle variable a été déterminée et à l'externe utile, même si elle n'est pas abordée dans le code.