Intel x86 Assembly Language & Microarchitecture
Optimisation
Recherche…
Introduction
Remarques
En cas de doute, vous pouvez toujours vous reporter au manuel de référence sur l’optimisation des architectures d’Intel 64 et IA-32 , qui est une excellente ressource de la société derrière l’architecture x86.
Remise à zéro d'un registre
La manière évidente de mettre un registre à zéro est de MOV dans un 0 - par exemple:
B8 00 00 00 00 MOV eax, 0
Notez qu'il s'agit d'une instruction de 5 octets.
Si vous souhaitez contourner les indicateurs ( MOV n'affecte jamais les indicateurs), vous pouvez utiliser l'instruction XOR pour XOR-bit au niveau du registre avec lui-même:
33 C0 XOR eax, eax
Cette instruction ne nécessite que 2 octets et s'exécute plus rapidement sur tous les processeurs .
Déplacer le drapeau Carry dans un registre
Contexte
Si le drapeau Carry ( C ) contient une valeur que vous souhaitez mettre dans un registre, la méthode naïve consiste à faire quelque chose comme ceci:
mov al, 1
jc NotZero
mov al, 0
NotZero:
Utilisez 'sbb'
Une manière plus directe, en évitant le saut, consiste à utiliser "Subtract with Borrow":
sbb al,al ; Move Carry to al
Si C est zéro, alors al sera zéro. Sinon, ce sera 0xFF ( -1 ). Si vous en avez besoin pour être 0x01 , ajoutez:
and al, 0x01 ; Mask down to 1 or 0
Avantages
- A peu près la même taille
- Deux ou un instructions en moins
- Pas de saut coûteux
Les inconvénients
- C'est opaque pour un lecteur peu familier avec la technique
- Il modifie les autres drapeaux
Tester un registre pour 0
Contexte
Pour savoir si un registre contient un zéro, la technique naïve consiste à le faire:
cmp eax, 0
Mais si vous regardez l'opcode pour cela, vous obtenez ceci:
83 F8 00 cmp eax, 0
Utiliser le test
test eax, eax ; Equal to zero?
Examinez l'opcode que vous obtenez:
85 c0 test eax, eax
Avantages
- Seulement deux octets!
Les inconvénients
- Opaque pour un lecteur peu familier avec la technique
Vous pouvez également jeter un œil à la question Q & R sur cette technique .
Appels système Linux avec moins de ballonnement
Dans Linux 32 bits, les appels système sont généralement effectués à l’aide de l’instruction sysenter (je dis généralement que les anciens programmes utilisent le maintenant int 0x80 déconseillé int 0x80 ), mais cela peut prendre beaucoup de place dans un programme. peut raccourcir pour raccourcir et accélérer les choses.
C'est généralement la disposition d'un appel système sur Linux 32 bits:
mov eax, <System call number>
mov ebx, <Argument 1> ;If applicable
mov ecx, <Argument 2> ;If applicable
mov edx, <Argument 3> ;If applicable
push <label to jump to after the syscall>
push ecx
push edx
push ebp
mov ebp, esp
sysenter
C'est énorme! Mais il y a quelques astuces que nous pouvons tirer pour éviter ce désordre.
La première consiste à définir ebp à la valeur de esp diminuée de la taille de 3 registres 32 bits, soit 12 octets. C'est génial tant que vous ne voulez pas écraser ebp, edx et ecx avec des erreurs (par exemple lorsque vous déplacez une valeur dans ces registres de toute façon), nous pouvons le faire en utilisant l'instruction LEA pour ne pas avoir besoin pour affecter la valeur de ESP lui-même.
mov eax, <System call number>
mov ebx, <Argument 1>
mov ecx, <Argument 2>
mov edx, <Argument 3>
push <label to jump to after the syscall>
lea ebp, [esp-12]
sysenter
Cependant, nous n'avons pas fini, si l'appel système est sys_exit, nous pouvons éviter de pousser n'importe quoi sur la pile!
mov eax, 1
xor ebx, ebx ;Set the exit status to 0
mov ebp, esp
sysenter
Multipliez par 3 ou 5
Contexte
Pour obtenir le produit d'un registre et d'une constante et le stocker dans un autre registre, la manière naïve consiste à le faire:
imul ecx, 3 ; Set ecx to 5 times its previous value
imul edx, eax, 5 ; Store 5 times the contend of eax in edx
Utiliser lea
Les multiplications sont des opérations coûteuses. Il est plus rapide d'utiliser une combinaison de changements et d'ajouts. Pour le cas particulier de multiplication du contenu d'un registre 32 ou 64 bits qui n'est pas esp ou rsp de 3 ou 5, vous pouvez utiliser l'instruction lea. Cela utilise le circuit de calcul d'adresse pour calculer le produit rapidement.
lea ecx, [2*ecx+ecx] ; Load 2*ecx+ecx = 3*ecx into ecx
lea edx, [4*edx+edx] ; Load 4*edx+edx = 5*edx into edx
De nombreux assembleurs comprendront aussi
lea ecx, [3*ecx]
lea edx, [5*edx]
Pour tous les multiplicables possibles autres que ebp ou rbp , la rbp l'instruction résultante est la même qu'avec l'utilisation d' imul .
Avantages
- Exécute beaucoup plus vite
Les inconvénients
- Si votre multiplicande est
ebpourbpil faut un octet de plus en utilisantimul - Plus à taper si votre assembleur ne prend pas en charge les raccourcis
- Opaque pour un lecteur peu familier avec la technique