Question Quel est le but de l'instruction LEA?


Pour moi, il semble juste comme un MOV funky. Quel est son but et quand devrais-je l'utiliser?


531
2017-11-01 20:57


origine


Réponses:


Comme d'autres l'ont souligné, LEA (load effective address) est souvent utilisé comme un «truc» pour faire certains calculs, mais ce n'est pas son objectif principal. L'ensemble d'instructions x86 a été conçu pour prendre en charge des langages de haut niveau tels que Pascal et C, où les tableaux, en particulier les tableaux d'entiers ou de petites structures, sont courants. Considérons, par exemple, une structure représentant les coordonnées (x, y):

struct Point
{
     int xcoord;
     int ycoord;
};

Maintenant, imaginez une déclaration comme:

int y = points[i].ycoord;

points[] est un tableau de Point. En supposant que la base du tableau est déjà dans EBXet variable i est dans EAX, et xcoord et ycoord sont chaque 32 bits (donc ycoord est à offset 4 octets dans la structure), cette instruction peut être compilée pour:

MOV EDX, [EBX + 8*EAX + 4]    ; right side is "effective address"

qui atterrira y dans EDX. Le facteur d'échelle de 8 est parce que chaque Point est de 8 octets. Considérons maintenant la même expression utilisée avec l'opérateur "address of" &:

int *p = &points[i].ycoord;

Dans ce cas, vous ne voulez pas la valeur de ycoord, mais son adresse. C'est là que LEA (charger l'adresse effective) entre en jeu. Au lieu d'un MOV, le compilateur peut générer

LEA ESI, [EBX + 8*EAX + 4]

qui va charger l'adresse dans ESI.


651
2017-11-03 06:25



Du "Zen de l'Assemblée" par Abrash:

LEA, la seule instruction qui effectue des calculs d'adressage de mémoire mais n'adresse pas réellement la mémoire. LEA accepte un opérande d'adressage de mémoire standard, mais ne fait rien de plus que stocker le décalage de mémoire calculé dans le registre spécifié, qui peut être n'importe quel registre général.

Qu'est-ce que cela nous donne? Deux choses qui ADD ne fournit pas:

  1. la possibilité d'effectuer des ajouts avec deux ou trois opérandes, et
  2. la possibilité de stocker le résultat dans tout registre; pas seulement l'un des opérandes de la source.

Et LEA ne modifie pas les drapeaux.

Exemples

  • LEA EAX, [ EAX + EBX + 1234567 ] calcule EAX + EBX + 1234567 (c'est trois opérandes)
  • LEA EAX, [ EBX + ECX ] calcule EBX + ECX sans passer outre avec le résultat.
  • multiplication par constante (par deux, trois, cinq ou neuf), si vous l'utilisez comme LEA EAX, [ EBX + N * EBX ] (N peut être 1,2,4,8).

Autre usecase est pratique dans les boucles: la différence entre LEA EAX, [ EAX + 1 ] et INC EAX est que ce dernier change EFLAGS mais le premier ne le fait pas; cela préserve CMP Etat.


460
2017-11-01 21:03



Une autre caractéristique importante de LEA instruction est qu'il ne modifie pas les codes de condition tels que CF et ZF, tout en calculant l'adresse par des instructions arithmétiques comme ADD ou MUL Est-ce que. Cette fonctionnalité diminue le niveau de dépendance entre les instructions et laisse donc la place à une optimisation supplémentaire par le compilateur ou le planificateur matériel.


86
2017-10-09 17:35



Malgré toutes les explications, LEA est une opération arithmétique:

LEA Rt, [Rs1+a*Rs2+b] =>  Rt = Rs1 + a*Rs2 + b

C'est juste que son nom est extrêmement stupide pour un changement + ajout d'opération. La raison de cela a déjà été expliquée dans les réponses les mieux notées (c'est-à-dire qu'elle a été conçue pour mapper directement des références de mémoire de haut niveau).


70
2017-08-15 21:43



Peut-être juste une autre chose à propos de l'instruction LEA. Vous pouvez également utiliser LEA pour des registres multiplicateurs rapides de 3, 5 ou 9.

LEA EAX, [EAX * 2 + EAX]   ;EAX = EAX * 3
LEA EAX, [EAX * 4 + EAX]   ;EAX = EAX * 5
LEA EAX, [EAX * 8 + EAX]   ;EAX = EAX * 9

64
2017-11-02 10:16



lea est une abréviation de "load effective address". Il charge l'adresse de la référence de localisation par l'opérande source à l'opérande de destination. Par exemple, vous pouvez l'utiliser pour:

lea ebx, [ebx+eax*8]

bouger ebx aiguille eax éléments supplémentaires (dans un tableau 64 bits / élément) avec une seule instruction. Fondamentalement, vous bénéficiez de modes d'adressage complexes pris en charge par l'architecture x86 pour manipuler efficacement les pointeurs.


51
2017-11-01 21:00



La plus grande raison que vous utilisez LEA au cours d'une MOV est si vous devez effectuer l'arithmétique sur les registres que vous utilisez pour calculer l'adresse. Effectivement, vous pouvez effectuer ce qui équivaut à arithmétique pointeur sur plusieurs des registres en combinaison efficace pour "libre".

Ce qui est vraiment déroutant à ce sujet est que vous écrivez généralement un LEA juste comme un MOV mais vous n'êtes pas en train de déréférencer la mémoire. En d'autres termes:

MOV EAX, [ESP+4]

Cela va déplacer le contenu de ce ESP+4 pointe vers EAX.

LEA EAX, [EBX*8]

Cela déplacera l'adresse effective EBX * 8 dans EAX, pas ce qui se trouve dans cet endroit. Comme vous pouvez le voir, il est également possible de multiplier par des facteurs de deux (scaling) MOV est limité à l'addition / soustraction.


19
2018-05-05 22:22



Le 8086 a une grande famille d'instructions qui accepte un opérande de registre et une adresse effective, effectue des calculs pour calculer la partie de décalage de cette adresse effective, et effectue une opération impliquant le registre et la mémoire référencés par l'adresse calculée. Il était assez simple d'avoir l'une des instructions de cette famille se comporter comme ci-dessus, sauf pour sauter cette opération de mémoire réelle. Ceci, les instructions:

mov ax,[bx+si+5]
lea ax,[bx+si+5]

ont été mis en œuvre presque à l'identique en interne. La différence est une étape sautée. Les deux instructions fonctionnent quelque chose comme:

temp = fetched immediate operand (5)
temp += bx
temp += si
address_out = temp  (skipped for LEA)
trigger 16-bit read  (skipped for LEA)
temp = data_in  (skipped for LEA)
ax = temp

Quant à savoir pourquoi Intel pensait que cette instruction valait la peine d'être comprise, je ne suis pas tout à fait sûr, mais le fait que ce soit peu coûteux à implémenter aurait été un facteur important. Un autre facteur aurait été le fait que l'assembleur d'Intel permettait de définir des symboles relatifs au registre BP. Si fnord a été défini comme un symbole relatif à BP (par exemple BP + 8), on pourrait dire:

mov ax,fnord  ; Equivalent to "mov ax,[BP+8]"

Si l'on voulait utiliser quelque chose comme stosw pour stocker des données à une adresse relative BP, être capable de dire

mov ax,0 ; Data to store
mov cx,16 ; Number of words
lea di,fnord
rep movs fnord  ; Address is ignored EXCEPT to note that it's an SS-relative word ptr

était plus pratique que:

mov ax,0 ; Data to store
mov cx,16 ; Number of words
mov di,bp
add di,offset fnord (i.e. 8)
rep movs fnord  ; Address is ignored EXCEPT to note that it's an SS-relative word ptr

Notez qu'oublier le "décalage" du monde entraînerait l'ajout du contenu de l'emplacement [BP + 8], plutôt que la valeur 8, à DI. Oops.


16
2018-04-29 19:46



Comme les réponses existantes mentionnées, LEA a l'avantage d'effectuer de l'arithmétique d'adressage mémoire sans accéder à la mémoire, sauvegarder le résultat arithmétique dans un registre différent au lieu de la simple forme d'instruction add. Le véritable avantage de la performance sous-jacente est que le processeur moderne dispose d'une unité LEA ALU séparée et d'un port pour une génération efficace d'adresses (y compris LEA et autre adresse de référence de mémoire), cela signifie l'opération arithmétique LEAet une autre opération arithmétique normale dans ALU pourrait être faite en parallèle dans un noyau.

Consultez cet article de l'architecture Haswell pour plus de détails sur l'unité LEA: http://www.realworldtech.com/haswell-cpu/4/

Un autre point important qui n'est pas mentionné dans d'autres réponses est LEA REG, [MemoryAddress] instruction est PIC (code indépendant de la position) qui code l'adresse relative PC dans cette instruction pour référence MemoryAddress. Ceci est différent de MOV REG, MemoryAddress qui code l'adresse virtuelle relative et nécessite de relocaliser / patcher dans les systèmes d'exploitation modernes (comme ASLR est une caractéristique commune). Alors LEA peut être utilisé pour convertir un non PIC en PIC.


10
2017-07-31 03:41



L'instruction LEA peut être utilisée pour éviter des calculs fastidieux d'adresses effectives par la CPU. Si une adresse est utilisée à plusieurs reprises, il est plus efficace de la stocker dans un registre au lieu de calculer l'adresse effective chaque fois qu'elle est utilisée.


7
2018-06-04 20:32